1.3 AOP产生的理由——传统方法存在的问题
下面通过分析传统方法存在的问题,来说明AOP产生的理由。
1.3.1 多维需求一维实现
虽然横切关注点会跨越多个模块,但当前的技术倾向于使用一维的方法学来处理这种需求,即把对应需求的实现强行限制在一维的空间里。这个一维空间就是核心模块的实现,其他需求的实现代码被嵌入在这个占统治地位的空间里。换句话说,需求空间是一个n维空间,而实现空间是一维空间,这种不匹配导致了糟糕的需求到实现的映射。
1.3.2 用传统方式实现
让我们来看一个简单且具体的例子,考虑一个封装了业务逻辑的类的实现框架。
public class Business extends IBusiness { //核心数据成员 //日志流 //权限对象 //事务对象 public void doAction() { //记录日志 //权限检查 //事务代码 //执行核心操作 save(); load(); } public void save() { } public void load() { } }
在上面的代码中,我们注意到3个问题:
● 日志、权限、事务不是这个类的核心关注点;
● doAction()的实现做了许多核心操作之外的事,它要处理日志、权限、事务等一些外围操作,而且这些外围操作同样也会应用于其他类;
● save()和load()执行的操作是否构成这个类的核心。
1.3.3 传统方式带来的问题
上面的代码将核心代码与日志、权限、事务的代码混在一起,造成了以下两大类问题。
● 代码混乱:软件系统中的模块可能要同时兼顾几个方面的需要。举例来说,开发者经常要同时考虑业务逻辑、性能、同步、日志和安全等问题,兼顾各方面的需要导致相应关注点的实现元素同时出现,引起代码混乱;
● 代码分散:由于横切关注点的存在,本来就涉及到多个模块,相关实现也就遍布在这些模块里,如在一个使用了数据库的系统里,性能问题就会影响所有访问数据库的模块,这导致代码分散在各处。
1.3.4 传统方式导致的结果
混乱和分散的代码会在多个方面影响系统的设计和开发,会产生以下几个的不良结果。
● 可读性差:由于同时实现几个关注点而模糊了不同关注点的实现,使得关注点与其实现之间的对应关系不明显;
● 编码效率低:同时实现几个关注点把开发人员的注意力从主要关注点转移到外围关注点,导致产能降低;
● 代码重用率低:在这种情况下,由于一个模块实现多个关注点,其他需要类似功能的系统不能马上使用该模块,进一步降低了产能;
● 代码质量差:混乱的代码掩盖了代码中隐藏的问题。而且,由于同时要处理多个关注点,应该特别注意的关注点得不到应有的关注;
● 难以扩展:狭窄的视角和有限的资源总是产生仅注意当前关注点的设计,新的需求导致重新实现。由于实现不是模块化的,也就是说实现牵涉到多个模块,为了新需求修改子系统可能会带来数据的不一致,而且还需相当规模的测试来保证这些修改不会带来Bug。
1.3.5 现有的3种解决办法
由于在多数系统中都包含横切关注点,自然地已经形成了一些技术来模块化横切关注点的实现,这些技术包括:混入类、设计模式和面向特定问题域的解决方式。
● 使用混入类:如使用Log4j,则可以推迟关注点的最终实现。基本类包含一个混入类的实例,允许系统的其他部分设置这个实例。举个例子来说,实现业务逻辑的类包含一个混入的Logger,系统的其他部分可以设置这个Logger已得到合适的日志类型,比如Logger可能被设置为使用文件系统或是消息中间件。在这种方式下,虽然日志的具体实现被推迟了,但基本类还是得包含在所有的写日志的点调用日志操作和控制日志信息的代码中;
● 行为型设计模式:如Visitor和Template模式,也允许你推迟具体实现。但是就像混入类一样,其操作的控制、调用Visitor或Template的逻辑,仍然留给了基本类;
● 面向特定问题域的解决方式:如框架和应用服务器,允许开发者用更模块化的方式处理某些横切关注点。比如EJB(Enterprise JavaBean,企业级JavaBean)架构,可以处理安全、系统管理、性能和容器管理的持久化(Container Managed Persistence)等横切关注点。Bean的开发者仅需关心业务逻辑,而部署者仅需关心部署问题,如Bean与数据库的映射。但是在大多数情况下,开发者还是要了解存储结构的。在这种方式下,你可以用基于XML的映射关系描述器来实现与数据持久化相关的横切关注点。
面向特定问题域的解决方式提供了解决特定问题的专门机制,它的缺点是对于每一种这样的解决方式开发人员都必须重新学习。另外,由于这种方式是与特定问题域相关的,属于特定问题域之外的横切关注点需要特殊的对待。
1.3.6 AOP能更好地解决问题
由上可见,为了解决传统方式存在的问题,我们使用混入类、行为型设计模式或特定问题的解决方法来从系统中分离出关注点。它们从一定范围上抽取了关注点的实现代码,但是基本类依然要增加对关注点代码的引用,显然它们并不能彻底摆脱传统方法所带来的问题。
因此,面向方面的编程(Aspect Oriented Programming,AOP)就应运而生了,它能够更好地解决这个问题。AOP为开发者提供了一种描述横切关注点的机制,并能够自动将横切关注点织入到面向对象的软件系统中,从而实现横切关注点的模块化。开发者可以在编译时更改、插入或除去系统的Aspect,甚至重用系统的Aspect。
因此,有了AOP,业务逻辑将彻底抛弃关注点的代码,可以全神贯注地关注核心问题,不用再为关注点分神了。