代理模式、动态代理和面向方面
代理的意思很好理解,它借鉴了我们日常所用的代理的意思:就是本来该自己亲自去做的某件事,由于某种原因不能直接做,而只能请人代替你做,这个被你请来做事的人就是代理。比如过春节要回家,由于你要上班,没时间去买票,就得票务中介代你购买,这就是一种代理模式。这个情景可以形象的描述如下:
class:火车站
{
卖票:
{……}
}
火车站是卖票的地方,我们假设只能在火车站买到票。卖票的动作实质是火车站类完成的。
Class:票务中介
{
卖票:
{
收中介费;
火车站.卖票;
}
}
顾客找票务中介买票的时候,调用票务中介.卖票。票务中介其实做了两件事,一是去火车站买票,二是不能白帮你卖票,肯定要收中介费。而你得到的好处是不用直接去火车站买票,节省了买票的时间用来上班。
以上我们简单模拟了代理模式的情景和为什么要使用代理模式,下面我们以一个例子来具体分析一下JAVA中的代理模式。
假设有一个信息管理系统,用些用户有浏览信息的权限,有些用户有浏览、添加和修改信息的权限,还有些用户有除了上述的权限,还有删除信息的权限,那么我们最容易想到的做法如下:
public class ViewAction
{
//由userId计算权限
……
String permission = ……;
if(permission.equals(Constants.VIEW))
{
System.out.println(“You could view the information……”);
……
}
}
其他的动作都和浏览信息的动作差不多。我们来看这样的类,很容易看出它的一些缺点来:第一、它把权限计算和动作执行都放在一个类里,两者的功能相互混在一起,容易造成思路的混乱,而且修改维护和测试都不好;一句话来说,它不满足单一职责原则。第二是客户调用的时候依赖具体的类,造成扩展和运行期内的调用的困难,不满足依赖颠倒原则。
既然有这么多的问题,我们有必要对该类进行重新设计。其实大家早已想到,这个类应该使用代理模式。是啊,和我们买火车票的动作一样,动作类不能直接执行那个动作,而是要先检查权限,然后才能执行;先检查权限,后执行的那各类其实就是一个代理类,修改后的代码如下:
public interface Action
{
public void doAction();
}
首先是设计一个接口,用来满足依赖颠倒原则。
Public class ViewAction implements Action
{
public void doAction()
{
//做View的动作
System.out.println(“You could view the information……”);
……
}
}
这个类跟火车站一样,是动作的真实执行者。
Public class ProxyViewAction implements Action
{
private Action action = new ViewAction();
public void doAction()
{
//调用权限类的方法取得用户权限
if(Permission.getPermission(userId).equals(Constants.VIEW))
{
action.doAction();
}
}
}
这是代理类,很容易理解。在我们的ProxyViewAction类中,除了做了客户真正想要做的动作:doAction()以外,还进行了额外的动作检查用户的权限。而作核心动作doAction()是在一个干干净净的类:ViewAction中进行,这个类只做核心动作,对其他的不关心,满足了单一职责原则。
客户端通过调用代理类来执行动作,而代理类一是将权限判断和动作的执行分离开来,满足了单一职责原则;二是实现了一个接口,从而满足了依赖颠倒原则。比第一个思路好了很多。
代理又被称为委派,说的是代理类并不真正的执行那个核心动作,而是委派给另外一个类去执行,如ProxyView类中,ProxyView类并没有真正执行doAction()方法,而是交给ViewAction类去执行。
|