我们为什么需要AOP?
1.传统的面向对象有些什么缺点?
答:传统的面向对象编程把问题分成许多小的模块,但是因为模块之间有交互,所以不得不在对象中引入其他行为逻辑,比如说apache web服务器中的43个模块有39个依赖于验证逻辑,这些逻辑掺杂在一个类中,使我们阅读代码变得困难,因为这样会使类的职能变得晦涩不清。在原来,系统状态由很多全局变量控制,可是应用程序中的任意一行代码都可以修改这些全局变量,面向对象方法封装这些系统状态,把他们变成单独的对象,在这些对象中私有化系统状态,并且通过访问方法和逻辑来控制这些状态。尽管面向对象的这种封装带来了一定的好处,可是要把问题表示成完全模块化完全封装好的对象,还是存在一定困难,因为有些功能必须跨对象进行使用!而面向方面编程让你构建整洁的,封装好的对象没有多余的功能!
面向对象由于封装了属性的修改,不像原来谁都可以修改一些系统属性,这样我跟踪调试就很方便,因为你只需要跟踪谁调用了属性修改方法就可以了!
2.oop导致的问题?
答:(摘自精通aspectj)
以下这段英文翻译过来很清晰的描述了oop所解决不了的问题,我简单解释一下就是,当我们需要添加新功能时,必须往已有的类中加入本来不属于他所关注的点的新代码,距离来说就是一个产品类,他本来只要关注自己的功能就可以,当为了满足系统的某项需求,比如在对产品赋予价格的方法的时候必须log下这个信息,本来这个log动作是应该由某个系统级的类抽象出来的,因为这属于系统级的功能,可是为了达到这个要求,我们必须在书或者其他产品类的setPrice()方法中额外加入log.write()类似的方法!你自己想想,一个类本来不应该对他外部世界做任何了解的,你打出log说明你已经了解别人肯定要用他了,这样封装性就不好,同时比如说书这种商品只需要关注属于自己的逻辑就行了,打印log算什么书的逻辑,跟书有关吗?真是混帐,这样我们就称类被系统中多个关注点横切了,因为系统的功能要求类这样做,唉,面向对象就是有这点很难解决的问题!还有类似那些计时统计记录的信息,身份验证要加进来的话,各种产品子类必须跟着团团转,作出相应的修改!
当某个需求导致代码纠缠时,我们就说该需求横切了系统,就像日志代码分散在tomcat的整个源代码中!横切并不总是系统的主要需求,这就像应用软件要正常运作也不一定需要日志功能,但在用户身份验证这种情况下确实要求横切!
AOP是Object Oriented Programming(OOP)的补充。
OOP能够很好地解决对象的数据和封装的问题,却不能很好的解决Aspect("方面")分离的问题。下面举例具体说明。
比如,我们有一个Bank(银行)类。Bank有两个方法,deposit(存钱)和withdraw(取钱)。
类和方法的定义如下:
class Bank{
public float deposit(AccountInfo account, float money){
// 增加account账户的钱数,返回账户里当前的钱数
}
public float withdraw(AccountInfo account, float money){
// 减少account账户的钱数,返回取出的钱数
}
};
这两个方法涉及到用户的账户资金等重要信息,必须要非常小心,所以编写完上面的商业逻辑之后,项目负责人又提出了新的要求--给Bank类的每个重要方法加上安全认证特性。
于是,我们不得不分别在上面的两个方法中加入安全认证的代码。
类和方法的定义如下:
class Bank{
public float deposit(AccountInfo account, float money){
// 验证account是否为合法用户
// 增加account账户的钱数,返回账户里当前的钱数
}
public float withdraw(AccountInfo account, float money){
// 验证account是否为合法用户
// 减少account账户的钱数,返回取出的钱数
}
};
这两个方法都需要操作数据库,为了保持数据完整性,项目负责人又提出了新的要求--给Bank类的每个操作数据库的方法加上事务控制。
于是,我们不得不分别在上面的两个方法中加入安全认证的代码。
类和方法的定义如下:
class Bank{
public float deposit(AccountInfo account, float money){
// 验证account是否为合法用户
// Begin Transaction
// 增加account账户的钱数,返回账户里当前的钱数
// End Transaction
}
public float withdraw(AccountInfo account, float money){
// 验证account是否为合法用户
// Begin Transaction
// 减少account账户的钱数,返回取出的钱数
// End Transaction
}
};
我们看到,这些与商业逻辑无关的重复代码遍布在整个程序中。实际的工程项目中涉及到的类和函数,远远不止两个。如何解决这种问题?
我们首先来看看OOP能否解决这个问题。
我们利用Design Pattern的Template Pattern,可以抽出一个框架,改变上面的例子的整个设计结构。
类和方法的定义如下:
abstract class Base{
public float importantMethod(AccountInfo account, float money){
// 验证account是否为合法用户
// Begin Transaction
float result = yourBusiness(account, money)
// End Transaction
return result;
}
protected abstract float yourBusiness(AccountInfo account, float money);
};
Code 2.5 BankDeposit.java
class BankDeposit extends Base{
protected float yourBusiness(AccountInfo account, float money){
// 增加account账户的钱数,返回账户里当前的钱数
}
};
Code 2.6 BankWithdraw.java
class BankWithdraw extends Base{
protected float yourBusiness(AccountInfo account, float money){
// 减少account账户的钱数,返回取出的钱数
}
};
这里我们用一种很勉强的方法实现了认证和事务代码的重用。而且,有心的读者可能会注意到,这种方法的前提是,强制所有的方法都遵守同样的signature。
如果有一个转账方法transfer(AccountInfo giver, AccountInfo receiver, float money),由于transfer方法的signature不同于yourBusiness的signature,这个方法无法使用上面的框架。
这个例子中提到的认证,事务等方面,就是AOP所关心的Aspect。
AOP就是为了解决这种问题而出现的。AOP的目的就是--Separation of Aspects (or Separation of Concerns).