代理设计模式
一,代理设计模式简介:
- 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。
- 在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
- 代理模式涉及到的角色:
- 抽象角色:声明真实对象和代理对象的共同接口;
- 代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象 ==注: 同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他 的操作,相当于对真实对象进行封装。
- 真实角色:代理角色所代表的真实对象,是我们最终要引用的对象;
- 代理描述:代理类相当于中间人,并不具有客户真正需要真实存在的物体,只是手中握有资源,并能根据客户的要求,和真实的物体拥有者进行交流,传递信息!
二,代理分静态代理和动态代理。
- 静态代理:涉及角色有:抽象角色(抽象类),真实角色(继承抽象类),代理角色(继承抽象类);当然还有客户
- 代码练习:
1 //定义抽象角色 2 abstract class Subject{ 3 abstract public void request(); 4 } 5 6 7 //定义真实角色,继承抽象角色并重写起其方法 8 class RealSubject extends Subject{ 9 public void request() { 10 System.out.println("From real subject."); 11 } 12 } 13 14 15 //代理角色,继承同一对象 16 class ProxySubject extends Subject{ 17 18 // 以真实角色作为代理角色的属性 19 private RealSubject realSubject; 20 21 22 // 该方法封装了真实对象的request方法 23 public void request() { 24 25 //调用真实对象自己的方法,为真实角色附加的信息,也是代理类的给你之一 26 preRequest(); 27 28 29 if (realSubject == null) { 30 realSubject = new RealSubject(); 31 } 32 33 34 // 此处执行真实对象的request方法 35 realSubject.request(); 36 37 //调用真实对象自己的方法,为真实角色附加的信息,也是代理类的给你之一 38 postRequest(); 39 } 40 41 private void preRequest() { 42 System.out.println("先前做的事情"); 43 } 44 private void postRequest() { 45 System.out.println("之后做的事情"); 46 } 47 } 48 49 50 51 //客户端 52 public class Client{ 53 public static void main(String[] args) 54 { 55 //多态,父类的引用指向子类的实例对象 56 Subject sub = new ProxySubject(); 57 sub.request(); 58 } 59 }
- 动态代理:Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类(接口算作特殊类):
- Interface InvocationHandler:该接口中仅定义了一个方法public object invoke(Object obj,Method method, Object[] args) ==注:第一个参数obj一般是指代理类,method是被代理的方法,==
- Proxy:该类即为动态代理类,作用类似于上例中的ProxySubject,其中主要包含以下内容:protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值;
- static Class getProxyClass (ClassLoader loader, Class[] interfaces): 获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组;
- static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h): 返回代理类的一个实例,返回后的代理类可以当作被代理类用(可使用被代理类的在Subject接口中声明过的方法)。
- 所谓动态代理类是这样一种类:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个动态代理类其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它管实际的工作。
- 涉及角色有:接口角色(这里是接口),具体角色(实现接口的类),代理处理器 (实现了调用处理器的类);当然还有客户(在这里动态实现代理类)
代码练习:
1 import java.lang.reflect.*; 2 3 //接口角色(之前是抽象类,此处应改为接口) 4 5 6 interface Subject { 7 public void request(); 8 } 9 10 11 //具体角色 12 class RealSubject implements Subject { 13 14 //构造函数 15 public RealSubject() { } 16 17 18 //复写接口中的方法 19 public void request() { 20 System.out.println("真正做事的。"); 21 } 22 } 23 24 25 /** 26 * 该代理类的内部属性为Object类,实际使用时通过该类的构造函数DynamicSubject(Object obj)对其赋值; 27 * 此外,在该类还实现了invoke方法,该方法中的 method.invoke(sub,args); 28 * 其实就是调用被代理对象的将要被执行的方法,方法参数sub是实际的被代理对象, 29 * args为执行被代理对象相应操作所需的参数。 30 * 通过动态代理类,我们可以在调用之前或之后执行一些相关操作 31 */ 32 33 class Dynamicsubject implements InvocationHandler { 34 35 //这里实现的是InvocationHandler接口 36 private Object sub; 37 38 public Dynamicsubject(Object obj) { 39 40 //重载构造函数 41 sub = obj; 42 } 43 44 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 45 46 47 //invoke()中的三个参数分别是代理类,代理方法,该方法的参数 48 System.out.println("调用前" + method); 49 50 51 method.invoke(sub, args); 52 53 System.out.println("调用后 " + method); 54 55 return null; 56 } 57 } 58 59 60 public class Client { 61 static public void main(String[] args) throws Throwable { 62 63 // 在这里指定被代理类 64 RealSubject rs = new RealSubject(); 65 66 //多态,父类的引用指向子类的实例对象 67 InvocationHandler ds = new Dynamicsubject(rs); 68 69 //通过反射得到代理类class文件 70 Class<?> cls = rs.getClass(); 71 72 // 以下是一次性生成代理 73 Subject subject = (Subject) Proxy.newProxyInstance( 74 //将代理类的类加载器,接口,调用处理器传入 75 cls.getClassLoader(), cls.getInterfaces(), ds); 76 77 subject.request(); 78 } 79 }
运行结果: 调用前public abstract void DynamicProxy.Subject.request()
真正做事的。
调用后 public abstract void DynamicProxy.Subject.request()
原理分析:
这个程序中把静态代理类的抽象类改变为一个接口,而实际类实现这个接口。是因为Proxy类的newProxyInstance方法传入需要提供一个接口;
Client类通过DynamicSubject类生成真实类的代理对象,并经由Proxy类的newProxyInstance方法实现
生成“一个能做真实类做的事的代理”,并由该代理直接调用真实类所具有的方法。