代理模式的核心思想与应用_第1页
代理模式的核心思想与应用_第2页
代理模式的核心思想与应用_第3页
代理模式的核心思想与应用_第4页
代理模式的核心思想与应用_第5页
已阅读5页,还剩5页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

12.3 代理模式(Proxy)本节从以下几个方面来详细讲解代理模式: 代理模式的核心思想。 何时使用代理模式。 Java中的应用Java动态代理机制。12.3.1 代理模式的核心思想代理模式就是给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。就是一个人或者一个机构代替另一个人或者另一个机构去采取一些行动。代理模式中的代理者就好比中介机构,它提供了对被代理对象的一切事物。代理模式与适配器模式和装饰器模式相似,它们之间的区别是: 适配器模式是将一个类A转换成另一个类B。 装饰器模式是为一个类A增加新的功能,从而变成类B。 代理模式是为一个类A转换操作类B。它们三者的限制条件层层递进,递进关系如图12-16所示。图12-16 代理模式递进关系代理模式中的“代理”要想实现代理任务,就必须与被代理的“对象”使用共同的接口。所以自然而然你会想到在Java中使用一个抽象类或者接口(推荐)来实现这个共同的接口。于是代理模式就有3个角色组成。 被代理对象的接口Sourcable:声明了代理对象和代理者的共同接口。 被代理对象Source:定义真实的对象。 代理者Proxy:内部包含对代理对象的引用,并且提供与代理对象角色相同的接口。使用类图来表示下三者间的关系如图12-17所示。图12-17 代理模式结构图下面来看具体的实现。(1)Sourcable类的源代码如程序12-28所示,其定义了一个接口函数operation()。程序12-28 源接口Sourcable.javapackage xy;/* author liuzhongbing* 源接口*/public interface Sourcable public void operation();(2)Source.java是Sourcable.java的一个实现,其函数operation()负责往控制台输出一个字符串:原始类的方法。其源代码如程序12-29所示。程序12-29 源类Source.javapackage xy;/* author liuzhongbing* 源类*/public class Source implements Sourcable public void operation() System.out.println(原始类的方法); (3)代理类Proxy.java采用了典型的对象适配器模式,它首先拥有一个Sourcable对象source,注意,不同的是该对象在构造函数中进行初始化,不能够从外部传入。然后它实现了Sourcable.java接口,以期保持与source同样的接口,并在重写的operation()函数中调用source的operation()函数,在调用前后可以调用自己的函数。其源代码如程序12-30所示。程序12-30 代理类Proxy.javapackage xy;/* author liuzhongbing* 代理模式*/public class Proxy implements Sourcable private Source source; /* * 创建代理对象 */ public Proxy() super(); this.source = new Source(); /* * 调用代理对象的方法 */ public void operation() before(); source.operation(); after(); public void before() System.out.println(代理前); public void after() System.out.println(代理后); 这时,我们就可以直接通过Proxy来操作Source类。如程序12-31所示,首先需要创建一个代理对象proxy,然后直接调用该对象的operation()方法,即可实现对source的调用。程序12-31 测试类Client.javapackage xy;/* author liuzhongbing*/public class Client public static void main(String args) / 创建代理对象 Sourcable proxy = new Proxy(); / 调用代理对象的方法 proxy.operation(); 运行该程序的结果如下:代理前原始类的方法代理后从程序的输出可以看出,通过Proxy不仅实现了对Source的调用,还实现了自身的功能,这与装饰器模式很相似,不同的是它们的关注点不同:装饰器模式关注于扩展功能,而代理模式关注于如何调用。12.3.2 何时使用代理模式在对已有的方法进行使用的时候需要对原有方法进行改进或者修改,这时候有两种改进选择:修改原有方法来适应现在的使用方式,或者使用一个“第三者”方法来调用原有的方法,并且对方法产生的结果进行一定的控制。第一种方法明显违背了“对扩展开放、对修改关闭”的开闭原则,而且在原有方法中进行修改可能使得原来类的功能变得模糊和多元化,而使用第二种方式可以将功能划分得更加清晰,有助于后面的维护。所以在一定程度上第二种方式是一个比较好的选择!这就是代理模式。如果按照使用目的来划分,代理有以下几种。 远程(Remote)代理:为一个位于不同的地址空间的对象提供一个局域代表对象。这个不同的地址空间可以在本机器中,也可以在另一台机器中。远程代理又叫做大使(Ambassador)。 虚拟(Virtual)代理:根据需要创建一个资源消耗较大的对象,使得此对象只在需要时才会被真正创建。 Copy-on-Write代理:虚拟代理的一种。把复制(克隆)拖延到只有在客户端需要时才真正采取行动。 保护(Protect or Access)代理:控制对一个对象的访问,如果需要,可以给不同的用户提供不同级别的使用权限。 Cache代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。 防火墙(Firewall)代理:保护目标,不让恶意用户接近。 同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。 智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。在所有种类的代理模式中,虚拟(Virtual)代理、远程(Remote)代理、智能引用代理(Smart Reference Proxy)和保护(Protect or Access)代理是最为常见的代理模式。12.3.3 Java中的应用Java动态代理机制Java引入了名为动态代理类(Dynamic Proxy Class)的新特性,利用它可为已知接口的实现动态地创建代理类。所谓动态代理,即通过代理类:Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联。Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类: 接口InvocationHandler:该接口中仅定义了一个方法:Object invoke(Object obj, Method method, Object args);在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。 Proxy:该类即为动态代理类,作用类实现了InvocationHandler接口的代理类,其中主要包含以下函数。 protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。 static Class getProxyClass (ClassLoader loader, Class interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。 static Object newProxyInstance(ClassLoader loader, Class interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当做被代理类使用。所谓Dynamic Proxy是这样一种类:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当做这些interface中的任何一个来用。当然,这个Dynamic Proxy其实就是一个Proxy,它不会替你做实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。下面的代码演示了用动态代理来创建一个代理类DynamicProxy。我们创建的这个DynamicProxy类不需要实现Sourcable接口,而是实现了java.lang.reflect.InvocationHandler,只提供了一个invoke()方法。代理对象上的任何方法调用都要通过这一方法进行。观察invoke()的主体,它包含了被调用方法的反射参数Method,我们可以使用该参数确定当前执行方法的属性。然而,我们得到的仍然只是一个具有invoke()方法的InvocationHandler,而不是我们真正想要的Sourcable对象。动态代理真正的魅力要到创建实际的Sourcable实例时才能反映出来。它通过调用DynamicProxy的构造方法初始化了被包装的对象proxyed。完整的代码如程序12-32所示。程序12-32 动态代理类DynamicProxy.javapackage xy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class DynamicProxy implements InvocationHandler private Object proxyed; / 被代理对象 public DynamicProxy(Object obj) xyed = obj; / 代理调用 public Object invoke(Object proxy, Method method, Object args) throws Throwable Object result; / 方法调用之前 System.out.println(start invoke!); / 调用原始对象的方法 result = method.invoke(xyed, args); / 方法调用之后 System.out.println(end invoke!); return result; 然后我们就可以像程序12-33一样进行代理调用。程序12-33 测试类DynamicProxyClient.javapackage xy;import java.lang.reflect.InvocationHandler;public class DynamicProxyClient public static void main(String args) / 创建原始类对象 Sourcable source = new Source(); / 创建代理实例 InvocationHandler handler = new DynamicProxy(source); / 取得代理对象 Sourcable proxy = (Sourcable) java.lang.reflect.Proxy.newProxyInstance(source.getClass() .getClassLoader(), source.getClass().getInterfaces(), handler); proxy.operation(); 这段代码实现了对目标对象source的代理调用: 根据被代理对象source创建一个代理类handler,此处是DynamicProxy对象。 创建动态代理对象proxy,它的第一个对象为source类的加载器,第二个对象为该类的接口,第三个对象为代理对象handler。 通过动态代理对象proxy调用operation()方法,此时会在原始对象Source. operation ()方法前后输出两句字符串。运行这段代码的输出是:start invoke!原始类的方法end invoke!上面的代码表面上看很复杂,但它的作用其实很简单,就是告诉DynamicProxy类用一个指定的类加载器来动态创建一个对象,该对象要实现指定的接口(本例为Soucable),并用提供的InvocationHandler来代替传统的方法主体。结果对象在一个instanceof Soucable测试中返回true,并提供在实现了Soucable接口的任何类中都能找到的方法。有趣的是,在DynamicProxy类的invoke()方法中,完全不存在对Soucable接口的引用。在本例中,我们以

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论