代理模式、动态代理和面向方面

上传人:子 文档编号:42048634 上传时间:2018-05-31 格式:DOC 页数:10 大小:37.50KB
返回 下载 相关 举报
代理模式、动态代理和面向方面_第1页
第1页 / 共10页
代理模式、动态代理和面向方面_第2页
第2页 / 共10页
代理模式、动态代理和面向方面_第3页
第3页 / 共10页
代理模式、动态代理和面向方面_第4页
第4页 / 共10页
代理模式、动态代理和面向方面_第5页
第5页 / 共10页
点击查看更多>>
资源描述

《代理模式、动态代理和面向方面》由会员分享,可在线阅读,更多相关《代理模式、动态代理和面向方面(10页珍藏版)》请在金锄头文库上搜索。

1、代理模式、动态代理和面向方面代理模式、动态代理和面向方面代理模式、动态代理和面向方面代理的意思很好理解,它借鉴了我们日常所用的代理的意思:就是本来该自己亲自去做的某件事,由于某种原因不能直接做,而只能请人代替你做,这个被你请来做事的人就是代理。比如过春节要回家,由于你要上班,没时间去买票,就得票务中介代你购买,这就是一种代理模式。这个情景可以形象的描述如下: class:火车站 卖票: 火车站是卖票的地方,我们假设只能在火车站买到票。卖票的动作实质是火车站类完成的。 Class:票务中介 卖票: 收中介费; 火车站.卖票; 顾客找票务中介买票的时候,调用票务中介.卖票。票务中介其实做了两件事,

2、一是去火车站买票,二是不能白帮你卖票,肯定要收中介费。而你得到的好处是不用直接去火车站买票,节省了买票的时间用来上班。 以上我们简单模拟了代理模式的情景和为什么要使用代理模式,下面我们以一个例子来具体分析一下 JAVA 中的代理模式。 假设有一个信息管理系统,用些用户有浏览信息的权限,有些用户有浏览、添加和修改信息的权限,还有些用户有除了上述的权限,还有删除信息的权限,那么我们最容易想到的做法如下: public class ViewAction /由 userId 计算权限 String permission = ; if(permission.equals(Constants.VIEW)

3、System.out.println(“You could view the information”); 其他的动作都和浏览信息的动作差不多。我们来看这样的类,很容易看出它的一些缺点来:第一、它把权限计算和动作执行都放在一个类里,两者的功能相互混在一起,容易造成思路的混乱,而且修改维护和测试都不好;一句话来说,它不满足单一职责原则。第二是客户调用的时候依赖具体的类,造成扩展和运行期内的调用的困难,不满足依赖颠倒原则。 既然有这么多的问题,我们有必要对该类进行重新设计。其实大家早已想到,这个类应该使用代理模式。是啊,和我们买火车票的动作一样,动作类不能直接执行那个动作,而是要先检查权限,然后才

4、能执行;先检查权限,后执行的那各类其实就是一个代理类,修改后的代码如下: 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 A

5、ction private Action action = new ViewAction(); public void doAction() /调用权限类的方法取得用户权限 if(Permission.getPermission(userId).equals(Constants.VIEW) action.doAction(); 这是代理类,很容易理解。在我们的 ProxyViewAction 类中,除了做了客户真正想要做的动作:doAction()以外,还进行了额外的动作检查用户的权限。而作核心动作 doAction()是在一个干干净净的类:ViewAction 中进行,这个类只做核心动作,对

6、其他的不关心,满足了单一职责原则。 客户端通过调用代理类来执行动作,而代理类一是将权限判断和动作的执行分离开来,满足了单一职责原则;二是实现了一个接口,从而满足了依赖颠倒原则。比第一个思路好了很多。 代理又被称为委派,说的是代理类并不真正的执行那个核心动作,而是委派给另外一个类去执行,如 ProxyView 类中,ProxyView类并没有真正执行 doAction()方法,而是交给 ViewAction 类去执行。 我们再来看代理类 ProxyViewAction,可以看到它不仅依赖于接口 Action,而且依赖于具体的实现 ViewAction。这样对我们的系统扩展很不利,比如我们有 Ad

7、d 动作、Delete 动作、Modify 动作等等,我们需要对每一个动作都写一个代理类,而这些代理类都做同样的事情,先进行权限判断,然后再委派。所以我们需要对这些代理再进行一次抽象,让它只依赖接口 Action,而不依赖于具体的实现。 要实现这样的想法,我们需要将代理类中的具体实现提走,让代理的使用者在运行期提供具体的实现类,即所谓的依赖注入,如下: Public class ProxyAction implements Action private Action action; public ProxyAction(Action action) this.action = action;

8、public void doAction() /调用权限类的方法取得用户权限 if(Permission.getPermission(userId).equals(action.getClass().getName() action.doAction(); 这样,我们就将所有实现了 Action 接口的实现使用一个代理类来代理它们。除了 ViewAction 类能用,以后扩展的 AddAction、 ModifyAction、DeleteAction 类等等,都可以使用一个代理类:ProxyAction。 而我们的客户端类似如下: Action action = ProxyAction(new

9、 ViewAction); Action.doAction(); 通过对代理类的依赖注入,我们使得代理类初步有了一定扩展性。但是我们还要看到,这个代理类依赖于某一个确定的接口。这仍然不能满足我们的实际要求,如我们的系统的权限控制一般是整个系统级的,这样系统级的权限控制,我们很难在整个系统里抽象出一个统一的接口,可能会有多个接口,按照上面的代理模式,我们需要对每一个接口写一个代理类,同样,这些类的功能都是一样的。这显然不是一个好地解决办法。 基于上面的原因,我们需要解决一个系统在没有统一的接口的情况下,对一些零散的对象的某一些动作使用代理模式的问题。JAVA API 为我们引入了动态代理或动态委

10、派的技术。 动态代理的核心是 InvocationHandler 接口,要使用动态代理就必须实现该接口。这个接口的委派任务是在 invoke(Object proxy, Method m, Object args)方法里面实现的: /在调用核心功能之前作一些动作 /调用核心功能 m.invoke(obj, args); /在调用核心功能以后做一些动作 我们可以看到动态代理其实用的是反射机制来调用核心功能的:m.invoke(obj, args);正是这种反射机制的使用使得我们调用核心功能更加灵活,而不用依赖于某一个具体的接口,而是依赖于Object 对象。 下面我们来具体看看动态代理或动态委派

11、如何使用: public class ProxyAction implements InvocationHandler private Object action; public ProxyAction(Object action) this.action = action; public static Object getInstance(Object action) return Proxy.newProxyInstance(action.getClass().getClassLoader(), action.getClass().getInterfaces(),new ProxyActi

12、on(action); public Object invoke(Object proxy, Method m, Object args) throws Throwable Object result; try /在委派之前作动作,如权限判断等 System.out.println(“before method “ + m.getName(); /进行委派 result = m.invoke(action, args); catch (InvocationTargetException e) throw e.getTargetException(); catch (Exception e) t

13、hrow new RuntimeException(“unexpected invocation exception: “ + e.getMessage(); finally /在委派之后做动作 System.out.println(“after method “ + m.getName(); return result; 这个代理类,首先是实现了 InvocationHandler 接口;然后在getInstance()方法里得到了代理类的实例;在 invoke()方法里实现代理功能,也很简单。 下面我们来看客户端: Action action = (Action)ProxyAction.g

14、etInstance(new ViewAction(); Action.doAction(); 我们可以看到代理类对接口的依赖也转移到了客户端上,这样,代理类不依赖于某个接口。对于同样的代理类 ProxyAction,我们也可以有如下的客户端调用: Engine engine = (Engine)ProxyAction.getInstance(new EngineImpl(); Engine.execute(); 只要 engineImpl 类实现了 Engine 接口,就可以像上面那样使用。 现在我们可以看到,动态代理的确是拥有相当的灵活性。但我们同时也看到了,这个代理类写起来比较麻烦,而且

15、也差不多每次都写这样千篇一律的东西,只有委派前的动作和委派后的动作在不同的代理里有着不同,其他的东西都需要照写。如果这样的代理类写多了,也会有一些冗余代理。需要我们进一步优化,这里我们使用模板方法模式来对这个代理类进行优化,如下: public abstract class BaseProxy implements InvocationHandler private Object obj; protected BaseProxy(Object obj) this.obj = obj; public static Object getInstance(Object obj,InvocationH

16、andler instance) return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),instance); public Object invoke(Object proxy, Method m, Object args) throws Throwable / TODO Auto-generated method stub Object result; try System.out.println(“before method “ + m.getName(); this.doBegin(); result = m.invoke

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 生活休闲 > 科普知识

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号