设计模式之代理模式(Proxy )
2016-07-07 17:50
645 查看
概述
为其他对象提供一种代理来控制这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。代理模式主要分为两种:一种是静态代理,一种是动态代理。
1.静态代理
UML类图:上面UML图涉及的角色:
抽象角色(Subject):声明真实对象和代理对象的共同接口。
真实角色(RealSubject):代理角色所代表的真实对象,是我们最终要引用的对象。
代理角色(Proxy):代理对象角色内部含有对真实对象的引用,从而可以操作真实对象。同时代理对象提供与真实对象相同的接口以便在任何时候都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
代码示例:
package interview; interface Subject{ void operation(); } class RealSubject implements Subject{ @Override public void operation() { System.out.println("真实角色的请求方法被调用!"); } } class Proxy implements Subject{ private Subject subject; private void preOper(){ System.out.println("代理前执行操作!!"); } @Override public void operation() { preOper(); if(subject == null){ subject = new RealSubject(); } subject.operation(); afterOper(); } private void afterOper(){ System.out.println("代理后执行!!"); } } public class MainTest { public static void main(String arg[]) { Subject subject = new Proxy(); subject.operation(); } }
代码内容很简单,客户实际需要调用的是RealSubject中的operation方法,现在用Proxy来代理RealSubject类,同样达到目的。同时还封装了preOper()和afterOper()方法。
如果按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但实际使用时,一个真实的角色必须对应一个代理角色,如果大量使用会导致类的急剧膨胀,此外,如果事先并不知道真实角色,该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。
2.动态代理
在Java的动态代理机制中,有两个非常重要的类或接口,一个是InvocationHandler接口,另一个是Proxy类。每一个动态代理类都必须要实现InvocationHandler接口,当我们通过代理对象调用一个方法时,这个方法的调用就会被转发为由InvocationHandler的invoke方法来进行调用。
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
上面方法接收了三个参数:
proxy:我们所代理的真实对象
method:我们所要调用真实对象的某个方法的Method对象
args:调用真是对象某个方法时接受的参数
继续来看Proxy这个类:
作用就是动态创建一个代理对象的类,它提供了许多的方法,使用最多的是newProxyInstance 方法。
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
上面的方法同样接收了三个参数:
loader:类的加载器,来对生成的代理对象进行加载
interfaces:接口对象的数组,表示将要给需要代理的对象提供一组接口,如果我提供了一组接口给它,那么这个代理对象就实现了该接口,这样就能调用这组接口中的方法了。
h:InvocationHandler的对象,表示当我这个动态代理对象在调用方法的时候,会关联到那个InvocationHandler对象上。
代码示例:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface Subject{ void rent(); void hello(String str); } class RealSubject implements Subject{ public void rent() { System.out.println("i want to rent my house"); } public void hello(String str) { System.out.println("hello "+ str); } } class DynamicProxy implements InvocationHandler { //要代理的真实对象 private Object subject; //构造方法 public DynamicProxy(Object subject){ this.subject = subject; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 在代理真实对象前我们可以添加一些自己的操作 System.err.println("before rent my house"); System.err.println("Method:" + method); // 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用 method.invoke(subject, args); // 在代理真实对象后我们也可以添加一些自己的操作 System.err.println("after rent my house"); return null; } } public class Main { public static void main(String args[]) { // 我们要代理的真实对象 Subject realSubject = new RealSubject(); // 将需要代理的对象传进去,最后是通过该真实对象来调用其方法的 InvocationHandler handler = new DynamicProxy(realSubject); // 创建我们的代理对象 Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler); System.out.println(subject.getClass().getSimpleName()); subject.rent(); subject.hello("LiSi"); } }
执行输出结果:
$Proxy0
before rent my house
Method:public abstract void Subject.rent()
after rent my house
before rent my house
Method:public abstract void Subject.hello(java.lang.String)
after rent my house
i want to rent my house
hello LiSi
System.out.println(subject.getClass().getSimpleName()); 返回的并不是subject的对象,也不是InvocationHandler对象。它是通过Proxy.newProxyInstance创建的代理对象,在jvm运行时动态生成的一个对象,以$开头,Proxy为中,最后一个数字表示对象的标号。
由于我们在newProxyInstance第二个参数提供了一组接口,那么这个代理对象就会实现这组接口,所以可以强制转化为这组接口中的任意一个,即可以转化为Subject对象。
接着下面两个方法:
subject.rent();
subject.hello(“LiSi”);
这两个方法都是通过method.invoke(subject, args);执行的。这里是通过代理对象调用实现接口的方法,这时程序会跳转到代理对象关联到的handler中的invoke方法中执行。而handler中又接受了realSubject的参数,所以method.invoke(subject, args);执行的也就是realSubject的方法。
相关文章推荐
- PropertyChangeListener简单理解
- 什么是设计模式
- 设计模式之创建型模式 - 特别的变量问题
- 七、设计模式——装饰模式
- 设计模式总结
- 设计模式之创建型模式
- 浅谈设计模式的学习
- Ruby设计模式编程之适配器模式实战攻略
- 实例讲解Ruby使用设计模式中的装饰器模式的方法
- 设计模式中的模板方法模式在Ruby中的应用实例两则
- Ruby设计模式编程中对外观模式的应用实例分析
- 实例解析Ruby设计模式编程中Strategy策略模式的使用
- Ruby中使用设计模式中的简单工厂模式和工厂方法模式
- Ruby使用设计模式中的代理模式与装饰模式的代码实例
- 详解组合模式的结构及其在Ruby设计模式编程中的运用
- C# 设计模式系列教程-建造者模式
- C#编程中使用设计模式中的原型模式的实例讲解
- 使用设计模式中的工厂方法模式进行C#编程的示例讲解
- 实例解析C#设计模式编程中简单工厂模式的使用
- 详解C#设计模式编程中生成器模式的使用