设计模式之代理模式

在阎宏博士的《JAVA与模式》一书中开头是这样描述代理(Proxy)模式的:

  代理模式是对象的结构模式。代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。


代理模式的结构

  所谓代理,就是一个人或者机构代表另一个人或者机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

  代理模式类图如下:

  

  在代理模式中的角色:

  ●  抽象对象角色:声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。

  ●  目标对象角色:定义了代理对象所代表的目标对象。

  ●  代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象。


4,应用场景举例:

比如西门庆找潘金莲,那潘金莲不好意思答复呀,咋办,找那个王婆做代理,表现在程序上时是这样的体现的

先说说这个场景中的要素:一种类型的女人,潘金莲,王婆,西门庆,后来扩展的贾氏也和西门庆勾上了,我们是假设的,然后西门庆找潘金莲happy,但潘金莲不好意思直接,就找个王婆代理呗。我们看看具体代码。

先定义一种女人

Java代码  收藏代码
  1. package com.yangguangfu.proxy;  
  2. /** 
  3.  *  
  4.  * @author 阿福(trygf521@126.com)<br> 
  5.  *定义一种类型的女人,王婆和潘金莲都属于这个类型的女人 
  6.  */  
  7. public interface KindWoman {  
  8.       
  9.     //这种女人能做什么事情呢?  
  10.     public void makeEyesWithMan();//抛媚眼  
  11.       
  12.     public void happyWithMan();//和男人那个....  
  13.   
  14. }  

一种类型嘛,那肯定是接口,定义个潘金莲

Java代码  收藏代码
  1. package com.yangguangfu.proxy;  
  2. /** 
  3.  *  
  4.  * @author 阿福(trygf521@126.com)<br> 
  5.  *定义一个潘金莲是什么样的人 
  6.  */  
  7. public class PanJinLian  implements KindWoman{  
  8.   
  9.     @Override  
  10.     public void happyWithMan() {  
  11.         System.out.println("潘金莲和男人在做那个...");  
  12.           
  13.     }  
  14.   
  15.     @Override  
  16.     public void makeEyesWithMan() {  
  17.         System.out.println("潘金莲抛媚眼...");  
  18.           
  19.     }  
  20.   
  21. }  

再定义个丑陋的王婆

Java代码  收藏代码
  1. package com.yangguangfu.proxy;  
  2. /** 
  3.  *  
  4.  * @author 阿福(trygf521@126.com)<br> 
  5.  *王婆这个人老聪明了,她太老了,是个男人都看不上她, 
  6.  *但是她有智慧经验呀,他作为一类女人的代理! 
  7.  */  
  8. public class WangPo implements KindWoman {  
  9.       
  10.     private KindWoman kindWoman;  
  11.       
  12.     public WangPo(){  
  13.         //默认的话是潘金莲的代理  
  14.         this.kindWoman = new PanJinLian();  
  15.     }  
  16.     //她可以是KindWomam的任何一个女人的代理,只要你是这一类型  
  17.     public WangPo(KindWoman kindWoman){  
  18.         this.kindWoman = kindWoman;  
  19.     }  
  20.   
  21.     @Override  
  22.     public void happyWithMan() {  
  23.         //自己老了,干不了了,但可以叫年轻的代替。  
  24.         this.kindWoman.happyWithMan();  
  25.           
  26.     }  
  27.   
  28.     @Override  
  29.     public void makeEyesWithMan() {  
  30.         //王婆年纪大了,谁看她抛媚眼啊  
  31.         this.kindWoman.makeEyesWithMan();  
  32.           
  33.     }  
  34.   
  35. }  

 

两个女主角都上场了,该男主角了,定义个西门庆

Java代码  收藏代码
  1. package com.yangguangfu.proxy;  
  2. /** 
  3.  *  
  4.  * @author 阿福(trygf521@126.com)<br> 
  5.  *水浒传是这样写的:西门庆被潘金莲用竹竿敲了一下,西门庆看痴迷了,被王婆看到了,就开始撮合两人好事,王婆作为潘金莲的代理人收了不少好处费,那我们假设一下: 
  6.  *如果没有王婆在中间牵线,这两个不要脸的能成事吗?难说得很! 
  7.  */  
  8. public class XiMenQiang {  
  9.   
  10.     /** 
  11.      * @param args 
  12.      */  
  13.     public static void main(String[] args) {  
  14.         WangPo wangPo;  
  15.         //把王婆叫出来  
  16.          wangPo = new WangPo();  
  17.         //然后西门庆说,我要和潘金莲Happy,然后王婆就安排了西门庆丢筷子哪出戏:  
  18.         wangPo.makeEyesWithMan();  
  19.         //看到没有表面是王婆在做,其实爽的是潘金莲  
  20.         wangPo.happyWithMan();  
  21.           
  22.           
  23.   
  24.     }  
  25.   
  26. }  

 

那这就是活生生的一个例子,通过代理人实现了某种目的,如果真去了王婆这个中间环节,直接西门庆和潘金莲勾搭,估计很难成就武松杀嫂事件。

     那我们再考虑一下,水浒里面还有没有这类型的女人?有,卢俊义的老婆贾氏(就是和那个管家苟合的那个),这个名字起的:“贾氏”,那我们也让王婆做她的代理:

Java代码  收藏代码
  1. package com.yangguangfu.proxy;  
  2. /** 
  3.  *  
  4.  * @author 阿福(trygf521@126.com)<br> 
  5.  *定义一个贾氏是什么样的人 
  6.  */  
  7. public class JiaShi implements KindWoman {  
  8.   
  9.     @Override  
  10.     public void happyWithMan() {  
  11.         System.out.println("贾氏和男人在做那个...");  
  12.           
  13.     }  
  14.   
  15.     @Override  
  16.     public void makeEyesWithMan() {  
  17.         System.out.println("贾氏抛媚眼...");  
  18.           
  19.     }  
  20.   
  21.   
  22. }  

 

西门庆勾潘金莲又勾引贾氏

Java代码  收藏代码
  1. package com.yangguangfu.proxy;  
  2. /** 
  3.  *  
  4.  * @author 阿福(trygf521@126.com)<br> 
  5.  *水浒传是这样写的:西门庆被潘金莲用竹竿敲了一下,西门庆看痴迷了,被王婆看到了,就开始撮合两人好事,王婆作为潘金莲的代理人收了不少好处费,那我们假设一下: 
  6.  *如果没有王婆在中间牵线,这两个不要脸的能成事吗?难说得很! 
  7.  */  
  8. public class XiMenQiang {  
  9.   
  10.     /** 
  11.      * @param args 
  12.      */  
  13.     public static void main(String[] args) {  
  14.         WangPo wangPo;  
  15.         //把王婆叫出来  
  16.          wangPo = new WangPo();  
  17.         //然后西门庆说,我要和潘金莲Happy,然后王婆就安排了西门庆丢筷子哪出戏:  
  18.         wangPo.makeEyesWithMan();  
  19.         //看到没有表面是王婆在做,其实爽的是潘金莲  
  20.         wangPo.happyWithMan();  
  21.           
  22.           
  23.           
  24.         //西门庆勾引贾氏  
  25.         JiaShi jiaShi = new JiaShi();  
  26.         wangPo = new WangPo(jiaShi);  
  27.         wangPo.makeEyesWithMan();  
  28.         wangPo.happyWithMan();  
  29.   
  30.     }  
  31.   
  32. }  

 说完这个故事,那我总结一下,代理模式主要使用了java的多态,干活的是被代理类,代理类主要是接活,你让我干活,好,我交给幕后的类去干,你满意就成,那怎么知道被代理类能不能干呢?同根就成,大家知根知底,你能做啥,我能做啥都清楚得很,同样一个接口呗。好了不多说了,慢慢体会吧。

Proxy是比较有用途的一种模式,而且变种较多,应用场合覆盖从小结构到整个系统的大结构,Proxy是代理的意思,我们也许有代理服务器等概念,代理概念可以解释为:在出发点到目的地之间有一道中间层,意为代理.

设计模式中定义: 为其他对象提供一种代理以控制对这个对象的访问.

为什么要使用Proxy?
1.授权机制 不同级别的用户对同一对象拥有不同的访问权利,如Jive论坛系统中,就使用Proxy进行授权机制控制,访问论坛有两种人:注册用户和游客(未注册用户),Jive中就通过类似ForumProxy这样的代理来控制这两种用户对论坛的访问权限.

2.某个客户端不能直接操作到某个对象,但又必须和那个对象有所互动.
举例两个具体情况
(1)如果那个对象是一个是很大的图片,需要花费很长时间才能显示出来,那么当这个图片包含在文档中时,使用编辑器或浏览器打开这个文档,打开文档必须很迅速,不能等待大图片处理完成,这时需要做个图片Proxy来代替真正的图片.

(2)如果那个对象在Internet的某个远端服务器上,直接操作这个对象因为网络速度原因可能比较慢,那我们可以先用Proxy来代替那个对象.

总之原则是,对于开销很大的对象,只有在使用它时才创建,这个原则可以为我们节省很多宝贵的Java内存. 所以,有些人认为Java耗费资源内存,我以为这和程序编制思路也有一定的关系.

如何使用Proxy?
以Jive论坛系统为例,访问论坛系统的用户有多种类型:注册普通用户 论坛管理者 系统管理者 游客,注册普通用户才能发言;论坛管理者可以管理他被授权的论坛;系统管理者可以管理所有事务等,这些权限划分和管理是使用Proxy完成的.

-----------------

应用场景
现实世界中,秘书就相当于一个代理,老板开会,那么通知员工开会时间、布置会场、会后整理会场等等开会相关工作就可以交给秘书做,老板就只需要开会就行了,不需要亲自做那些事。同理,在我们程序设计中也可使用代理模式来将由一系列无关逻辑组合在一起的代码进行解耦合,比如业务代码中的日志代码就可以在代理中进行。Spring的AOP就是典型的动态代理应用。


代理模式的应用形式
(1)远程代理(Remote Proxy) -可以隐藏一个对象存在于不同地址空间的事实。也使得客户端可以访问在远程机器上的对象,远程机器可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。
(2)虚拟代理(Virtual Proxy) – 允许内存开销较大的对象在需要的时候创建。只有我们真正需要这个对象的时候才创建。
(3)写入时复制代理(Copy-On-Write Proxy) – 用来控制对象的复制,方法是延迟对象的复制,直到客户真的需要为止。是虚拟代理的一个变体。
(4)保护代理(Protection (Access)Proxy) – 为不同的客户提供不同级别的目标对象访问权限
(5)缓存代理(Cache Proxy) – 为开销大的运算结果提供暂时存储,它允许多个客户共享结果,以减少计算或网络延迟。
(6)防火墙代理(Firewall Proxy) – 控制网络资源的访问,保护主题免于恶意客户的侵害。
(7)同步代理(SynchronizationProxy) – 在多线程的情况下为主题提供安全的访问。
(8)智能引用代理(Smart ReferenceProxy) - 当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。
(9)复杂隐藏代理(Complexity HidingProxy) – 用来隐藏一个类的复杂集合的复杂度,并进行访问控制。有时候也称为外观代理(Façade Proxy),这不难理解。复杂隐藏代理和外观模式是不一样的,因为代理控制访问,而外观模式是不一样的,因为代理控制访问,而外观模式只提供另一组接口。
 
  

参考:

http://blog.csdn.net/jason0539/article/details/22974405

http://download.csdn.net/detail/tlk20071/9520157

http://download.csdn.net/detail/yjwffgip456/8422449

http://yangguangfu.iteye.com/blog/815787

http://www.cnblogs.com/java-my-life/archive/2012/04/23/2466712.html

原文地址:https://www.cnblogs.com/manmanlu/p/5867439.html