JAVA设计模式学习13——代理模式

2019-03-08 09:23|来源: 网络

代理(proxy)模式:指目标对象给定代理对象,并由代理对象代替真实对象控制客户端对真实对象的访问。

代理模式模式有以下角色:

抽象主题(subject)角色:声明真实主题和代理主题的共同接口。

真实主题(real subject)角色:定义代理对象需要代理的真实对象。

代理主题(proxy subject)角色:代替真实对象来控制对真实对象的访问,代理对象持有真实对象的应用,从而可以随时控制客户端对真实对象的访问。

代理模式结构类图:

代理模式在java里面很常见,在开源框架里如spring,mybatis等里面大量使用。现实生活中也很常见,比如我们访问facebook主站,常会选择一些代理,通过代理访问facebook。代理分静态代理和动态代理,java对动态代理有很好的支持,提供了InvocationHandler接口和Proxy类。

 

java API 对InvocationHandler接口和Proxy类的介绍:

 

Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。创建某一接口 Foo 的代理:

     InvocationHandler handler = new MyInvocationHandler(...);
     Class proxyClass = Proxy.getProxyClass(
         Foo.class.getClassLoader(), new Class[] { Foo.class });
     Foo f = (Foo) proxyClass.
         getConstructor(new Class[] { InvocationHandler.class }).
         newInstance(new Object[] { handler });
 

或使用以下更简单的方法:

     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
                                          new Class[] { Foo.class },
                                          handler);
 

动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。 代理接口 是代理类实现的一个接口。 代理实例 是代理类的一个实例。 每个代理实例都有一个关联的调用处理程序 对象,它可以实现接口 InvocationHandler。通过其中一个代理接口的代理实例上的方法调用将被指派到实例的调用处理程序的 Invoke 方法,并传递代理实例、识别调用方法的 java.lang.reflect.Method 对象以及包含参数的 Object 类型的数组。调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。InvocationHandler 是代理实例的调用处理程序 实现的接口。每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法。 

 

这里举个好理解的例子:公司项目部需要CEO签署一个文件,项目负责人会把文件交给CEO助理,助理会收文件,等到CEO回来后递CEO,CEO签署后交给助理,助理收好交给项目负责人。这个过程中项目负责人其实不知道是否真的是CEO签署的文件,有可能是助理打印的CEO的签名到文件上。这样助理就是一个代理角色,代替CEO处理事务。静态代理类图如下:

代码如下: 

Java代码 
  1. package proxy;  
  2.   
  3. /** 
  4.  
  5.  *  
  6.  
  7.  *作者:alaric 
  8.  
  9.  *时间:2013-7-24下午10:44:12 
  10.  
  11.  *描述:抽象主题 
  12.  
  13.  */  
  14.   
  15. public interface Leader {  
  16.   
  17.     public void sign();  
  18.   
  19. }  

 

Java代码 
  1. package proxy;  
  2. /** 
  3.  *  
  4.  *作者:alaric 
  5.  *时间:2013-7-24下午10:45:05 
  6.  *描述:ceo  真实主题 
  7.  */  
  8. public class CEO implements Leader {  
  9.   
  10.     @Override  
  11.     public void sign() {  
  12.         System.out.println("CEO签文件");  
  13.     }  
  14.   
  15. }  

 

Java代码 
  1. package proxy;  
  2. /** 
  3.  *  
  4.  *作者:alaric 
  5.  *时间:2013-7-24下午10:45:25 
  6.  *描述:代理主题 
  7.  */  
  8. public class Assistant implements Leader{  
  9.   
  10.     private Leader leader ;  
  11.       
  12.       
  13.     public Assistant(Leader leader) {  
  14.         super();  
  15.         this.leader = leader;  
  16.     }  
  17.   
  18.   
  19.     @Override  
  20.     public void sign() {  
  21.         System.out.println("递给领导");  
  22.         leader.sign();  
  23.         System.out.println("装入袋子,送出");  
  24.     }  
  25.       
  26.   
  27. }  

 

Java代码 
  1. package proxy;  
  2.   
  3. import java.lang.reflect.InvocationHandler;  
  4. import java.lang.reflect.Method;  
  5. import java.lang.reflect.Proxy;  
  6. /** 
  7.  *  
  8.  *作者:alaric 
  9.  *时间:2013-7-24下午10:46:04 
  10.  *描述:动态代理的Handler 
  11.  */  
  12. public class AssistantHandler implements InvocationHandler {  
  13.       
  14.     /** 
  15.      * 目标对象 
  16.      */  
  17.     private Object targetObject;    
  18.         
  19.      
  20.     /** 
  21.      *  
  22.      *作者:alaric 
  23.      *时间:2013-7-24下午10:46:59 
  24.      *描述:创建代理对象 这段也可以不在此类,也可以放在客户端里面 
  25.      */  
  26.     public Object createProxy(Object targetOjbect){    
  27.         this.targetObject = targetOjbect;    
  28.         return Proxy.newProxyInstance(targetOjbect.getClass().getClassLoader(),    
  29.                 targetOjbect.getClass().getInterfaces(), this);    
  30.     };    
  31.     
  32.    
  33.     /** 
  34.      * 此方法为必须实现的,在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。  
  35.      */  
  36.     @Override    
  37.     public Object invoke(Object proxy, Method method, Object[] args)    
  38.             throws Throwable {    
  39.         Object result = null;    
  40.         System.out.println("递给领导");  
  41.         result = method.invoke(this.targetObject, args);    
  42.         System.out.println("装入袋子,送出");  
  43.         return result;    
  44.     }    
  45.   
  46. }  

 

Java代码 
  1. package proxy;  
  2.   
  3. import java.lang.reflect.Proxy;  
  4.   
  5. /** 
  6.  *  
  7.  *作者:alaric 
  8.  *时间:2013-7-24下午10:44:37 
  9.  *描述:测试类  包括静态代理和动态代理 
  10.  */  
  11. public class Client {  
  12.   
  13.     /** 
  14.      * @param args 
  15.      */  
  16.     public static void main(String[] args) {  
  17.         //静态代理测试  
  18.         CEO ceo = new CEO();  
  19.         Leader leader1 = new Assistant(ceo);  
  20.         leader1.sign();  
  21.           
  22.         System.out.println("=========================================");  
  23.         //动态代理测试,一些三种方式都可以获得动态代理对象  
  24.         AssistantHandler ah = new AssistantHandler(ceo);  
  25.         //Leader leader2 = (Leader) ah.createProxy(new CEO());  
  26.         //leader2.sign();  
  27.       
  28.         //Leader leader3 = (Leader) Proxy.newProxyInstance(CEO.class.getClassLoader(),    
  29.         //      ceo.getClass().getInterfaces(), ah);    
  30.         //leader3.sign();  
  31.           
  32.         Leader leader4 = (Leader) Proxy.newProxyInstance(Leader.class.getClassLoader(),  
  33.                  new Class[] { Leader.class },  
  34.                  ah);  
  35.         leader4.sign();  
  36.           
  37.     }  
  38.   
  39. }  

 运行结果如下:

递给领导

CEO签文件

装入袋子,送出

=========================================

递给领导

CEO签文件

装入袋子,送出

通过上面例子和代码可以看出,动态代理显得更为灵活,实际过程中动态代理也较为常用。

 

 


转自:http://alaric.iteye.com/blog/1913048

相关问答

更多
  • 如果只是用spark处理数据,那不是很需要;如果要看spark的源代码,或者要将Spark运用在工程项目中进行工程化,那是很需要的
  • 其实我相信你做了3年的java一定了解你所说的设计模式和反射机制在程序早已用过了的把,只是自己平时没注意;设计模式主要是用项目管理,让人看起来通俗易懂.反射机制用到的地方呢也比较多,在用properties和JFreeChart等地方都用到.
  • 模式开扩了我们的视野,强化了我们面向对象编程的思维方式 提高代码的复杂度为代价来增强灵活性、可复用性 工厂模式根据工厂模式实现的类可以根据提供的数据 生成一组类中某一个类的实例,通常这组类有一个公共的 抽象父类或接口并且实现了相同的方法,但是这些方法针对不同 的数据进行了不同的操作。 首先需要定义一个基类,该类的子类通过不同的方法实现了 基类中的方法,然后需要定义一个工厂类,工厂类可以根据 条件生成不同子类的实例。 得到实例后,可以调用基类的方法而不必考虑到底 返回的是哪个子类的实例。 Factory(工厂 ...
  • 马学兵视频,W3C 教程,硅谷动力 视频教程等 先看视频,然后跟着做一遍。 最后下载一个 源码,尝试着模仿做几个 基本算入门了
  • 你是准备学习使用 还是说研究它的底层实现机制这些东西? 如果只是使用 可以暂时不了解这些 ,你也没有这么多精力来了解这么多 你先将框架中的东西用熟练 然后再去了解这些也不迟 spring 的 IOC aop hibernate的 延迟加载 缓存 ,mvc这些学习都需要学习 其实你学习不学习这几个框架都可以对设计模式进行学习 设计模式在日常的版本开发中好处很多 而且在面试的时候 考官也会问设计模式方面的知识
  • 一共23种设计模式! 引用《软件秘笈-设计模式那点事》书籍: 按照目的来分,设计模式可以分为创建型模式、结构型模式和行为型模式。 创建型模式用来处理对象的创建过程;结构型模式用来处理类或者对象的组合;行为型模式用来对类或对象怎样交互和怎样分配职责进行描述。 创建型模式用来处理对象的创建过程,主要包含以下5种设计模式:  工厂方法模式(Factory Method Pattern)  抽象工厂模式(Abstract Factory Pattern)  建造者模式(Builder Pattern)  原 ...
  • 一般来说电驴(verycd)里面可以下载,那里面的资源很多。希望这个对你有帮助
  • java mvc设计模式[2022-08-26]

    MVC模式写的 有是有 不过里面加入了简单工厂模式 呵呵不知道你要不要
  • 很简单:对外部提供统一的接口方法,而代理类在接口中实现对真实类的附加操作行为,从而可以在不影响外部调用情况下,进行系统扩展。也就是说,我要修改真实角色的操作的时候,尽量不要修改他,而是在外部在“包”一层进行附加行为,即代理类。 例如:接口A有一个接口方法operator(),真是角色:RealA实现接口A,则必须实现接口方法operator()。客户端Client调用接口A的接口方法operator()。 现在新需求来了,需要修改RealA中的operator()的操作行为。怎么办呢?如果修改RealA就会 ...
  • 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。 java设计模式是当你在实际的系统当中遇到重构或者扩展的时候采取的一种对现有系统影响最小的一种措施。当然并不是一定要学这个东西,就像一个没上过学的人和上过学的人,在个人修养上面存在一定的差异,但是他们都 ...