一、代理模式的内容

       代理模式为另一个对象提供一个替身或占位符以访问这个对象。
        给某一个对象提供一个代理,并由代理对象控制对原对象的引用。代理模式的英文叫做Proxy或Surrogate,它是一种对象结构型模式。
        所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
        一个例子就是Windows的快捷方式。快捷方式是它所引用的程序的一个代理。
  • 在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用。代理对象可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外服务。
  • 通过引入一个新的对象(如小图片和远程代理对象)来实现对真实对象的操作或者将新的对象作为真实对象的一个替身,这种实现机制即为代理模式,通过引入代理对象来间接访问一个对象,这就是代理模式的模式动机。

要点

  • 装饰者模式为对象加上行为,而代理模式则是控制访问。
  • 和装饰者模式类似,代理模式会造成设计中类的数目增加。

二、 代理的种类

如果按照使用目的来划分,代理有以下几种:

  • 远程(Remote)代理:为一个位于不同的地址空间的对象提供一个局域代表对象。这个不同的地址空间可以是在本机器中,也可是在另一台机器中。远程代理又叫做大使(Ambassador)。
  • 虚拟(Virtual)代理:根据需要创建一个资源消耗较大的对象,使得此对象只在需要时才会被真正创建。
  • Copy-on-Write代理:虚拟代理的一种。把复制(克隆)拖延到只有在客户端需要时,才真正采取行动。
  • 保护(Protect or Access)代理:控制对一个对象的访问,如果需要,可以给不同的用户提供不同级别的使用权限。
  • Cache代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。
  • 防火墙(Firewall)代理:保护目标,不让恶意用户接近。
  • 同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。
  • 智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。

在所有种类的代理模式中,虚拟(Virtual)代理、远程(Remote)代理、智能引用代理(Smart Reference Proxy)和保护(Protect or Access)代理是最为常见的代理模式。

三、代理模式的结构

代理模式所涉及的角色有:

抽象主题角色(Subject):声明了真实主题和代理主题的共同接口,这样一来在任何使用真实主题的地方都可以使用代理主题。

代理主题(Proxy)角色:代理主题角色内部含有对真是主题的引用,从而可以在任何时候操作真实主题对象;代理主题角色提供一个与真实主题角色相同的接口,以便可以在任何时候都可以替代真实主体;控制真实主题的应用,负责在需要的时候创建真实主题对象(和删除真实主题对象);代理角色通常在将客户端调用传递给真实的主题之前或之后,都要执行某个操作,而不是单纯的将调用传递给真实主题对象。

真实主题角色(RealSubject)角色:定义了代理角色所代表的真实对象。

四、代理模式示例代码

代码一、
抽象主题角色(Subject)
public interface AbstractPermission
{public void modifyUserInfo();public void viewNote();public void publishNote();public void modifyNote();public void setLevel(int level);
}

真实主题角色(RealSubject)角色

public class RealPermission implements AbstractPermission
{   public void modifyUserInfo(){System.out.println("修改用户信息!");}public void viewNote(){   }public void publishNote(){System.out.println("发布新帖!");}public void modifyNote(){System.out.println("修改发帖内容!");}public void setLevel(int level){   }
}

代理主题(Proxy)角色

public class PermissionProxy implements AbstractPermission
{private RealPermission permission=new RealPermission();private int level=0; public void modifyUserInfo(){if(0==level){System.out.println("对不起,你没有该权限!");}else if(1==level){permission.modifyUserInfo();}}public void viewNote(){System.out.println("查看帖子!");}public void publishNote(){if(0==level){System.out.println("对不起,你没有该权限!");}else if(1==level){permission.publishNote();}       }public void modifyNote(){if(0==level){System.out.println("对不起,你没有该权限!");}else if(1==level){permission.modifyNote();}      }public void setLevel(int level){this.level=level;}
}

测试

<?xml version="1.0"?>
<config><className>PermissionProxy</className>
</config>
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;
public class XMLUtil
{
//该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象public static Object getBean(){try{//创建文档对象DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = dFactory.newDocumentBuilder();Document doc;                           doc = builder.parse(new File("config.xml")); //获取包含类名的文本节点NodeList nl = doc.getElementsByTagName("className");Node classNode=nl.item(0).getFirstChild();String cName=classNode.getNodeValue();//通过类名生成实例对象并将其返回Class c=Class.forName(cName);Object obj=c.newInstance();return obj;}   catch(Exception e){e.printStackTrace();return null;}}
}
public class Client
{public static void main(String args[]){AbstractPermission permission;permission=(AbstractPermission)XMLUtil.getBean();permission.modifyUserInfo();permission.viewNote();permission.publishNote();permission.modifyNote();System.out.println("----------------------------");permission.setLevel(1);permission.modifyUserInfo();permission.viewNote();permission.publishNote();permission.modifyNote();}
}

代码二(动态代理)、

抽象主题

public interface AbstractSubject
{public void request();
}

真正主题

public class RealSubjectA implements AbstractSubject
{   public void request(){System.out.println("真实主题类A!");}
}
public class RealSubjectB implements AbstractSubject
{   public void request(){System.out.println("真实主题类B!");}
}

代理角色

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class DynamicProxy implements InvocationHandler
{private Object obj;public DynamicProxy(){}public DynamicProxy(Object obj){this.obj=obj;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{preRequest();method.invoke(obj, args);postRequest();return null;}public void preRequest(){System.out.println("调用之前!");}public void postRequest(){System.out.println("调用之后!");}}

测试

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;public class Client
{public static void main(String args[]){InvocationHandler handler =null;AbstractSubject subject=null;handler=new DynamicProxy(new RealSubjectA());subject=(AbstractSubject)Proxy.newProxyInstance(AbstractSubject.class.getClassLoader(), new Class[]{AbstractSubject.class}, handler);subject.request();System.out.println("------------------------------");handler=new DynamicProxy(new RealSubjectB());subject=(AbstractSubject)Proxy.newProxyInstance(AbstractSubject.class.getClassLoader(), new Class[]{AbstractSubject.class}, handler);subject.request();}
}

五、几种常用的代理模式

  • 图片代理:一个很常见的代理模式的应用实例就是对大图浏览的控制。

用户通过浏览器访问网页时先不加载真实的大图,而是通过代理对象的方法来进行处理,在代理对象的方法中,先使用一个线程向客户端浏览器加载一个小图片,然后在后台使用另一个线程来调用大图片的加载方法将大图片加载到客户端。当需要浏览大图片时,再将大图片在新网页中显示。如果用户在浏览大图时加载工作还没有完成,可以再启动一个线程来显示相应的提示信息。通过代理技术结合多线程编程将真实图片的加载放到后台来操作,不影响前台图片的浏览。

  • 远程代理:远程代理可以将网络的细节隐藏起来,使得客户端不必考虑网络的存在。客户完全可以认为被代理的远程业务对象是局域的而不是远程的,而远程代理对象承担了大部分的网络通信工作。
  • 虚拟代理:当一个对象的加载十分耗费资源的时候,虚拟代理的优势就非常明显地体现出来了。虚拟代理模式是一种内存节省技术,那些占用大量内存或处理复杂的对象将推迟到使用它的时候才创建。
        在应用程序启动的时候,可以用代理对象代替真实对象初始化,节省了内存的占用,并大大加速了系统的启动时间。
动态代理

  • 动态代理是一种较为高级的代理模式,它的典型应用就是Spring AOP。

在传统的代理模式中,客户端通过Proxy调用RealSubject类的request()方法,同时还在代理类中封装了其他方法(如preRequest()和postRequest()),可以处理一些其他问题。
        如果按照这种方法使用代理模式,那么真实主题角色必须是事先已经存在的,并将其作为代理对象的内部成员属性。如果一个真实主题角色必须对应一个代理主题角色,这将导致系统中的类个数急剧增加,因此需要想办法减少系统中类的个数,此外,如何在事先不知道真实主题角色的情况下使用代理主题角色,这都是动态代理需要解决的问题。

        Java动态代理实现相关类位于java.lang.reflect包,主要涉及两个类:

  1. InvocationHandler接口。它是代理实例的调用处理程序实现的接口,该接口中定义了如下方法:public Object invoke (Object proxy, Method method, Object[] args) throws Throwable;invoke()方法中第一个参数proxy表示代理类,第二个参数method表示需要代理的方法,第三个参数args表示代理方法的参数数组。
  2. Proxy类。该类即为动态代理类,该类最常用的方法为:public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException。newProxyInstance()方法用于根据传入的接口类型interfaces返回一个动态创建的代理类的实例,方法中第一个参数loader表示代理类的类加载器,第二个参数interfaces表示代理类实现的接口列表(与真实主题类的接口列表一致),第三个参数h表示所指派的调用处理程序类。

六、代理模式优缺点

代理模式的优点

  • 代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度。
  • 远程代理使得客户端可以访问在远程机器上的对象,远程机器可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。
  • 虚拟代理通过使用一个小对象来代表一个大对象,可以减少系统资源的消耗,对系统进行优化并提高运行速度。
  • 保护代理可以控制对真实对象的使用权限。
代理模式的缺点

  • 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
  • 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

七、代理模式适用环境

根据代理模式的使用目的,常见的代理模式有以下几种类型:

  1. 远程(Remote)代理:为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又叫做大使(Ambassador)。
  2. 虚拟(Virtual)代理:如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。
  3. Copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。
  4. 保护(Protect or Access)代理:控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。
  5. 缓冲(Cache)代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。
  6. 防火墙(Firewall)代理:保护目标不让恶意用户接近。
  7. 同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。
  8. 智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,如将此对象被调用的次数记录下来等。

八、代理模式应用

(1) Java RMI (Remote Method Invocation,远程方法调用)。

(2) EJB、Web Service等分布式技术都是代理模式的应用。在EJB中使用了RMI机制,远程服务器中的企业级Bean在本地有一个桩代理,客户端通过桩来调用远程对象中定义的方法,而无须直接与远程对象交互。在EJB的使用中需要提供一个公共的接口,客户端针对该接口进行编程,无须知道桩以及远程EJB的实现细节。 
(3) Spring 框架中的AOP技术也是代理模式的应用,在Spring AOP中应用了动态代理(Dynamic Proxy)技术。 

Proxy (recognizeable by creational methods which returns an implementation of given abstract/interface type which in turn delegates/uses a different implementation of given abstract/interface type)

  • java.lang.reflect.Proxy
  • java.rmi.*, the whole API actually.

The Wikipedia example is IMHO a bit poor, lazy loading has actually completely nothing to do with the proxy pattern at all.

九、参考资料

  1. 《设计模式》刘伟主编清华大学出版社
  2. 《Head First 设计模式》
  3. http://stackoverflow.com/questions/1673841/examples-of-gof-design-patterns

转载于:https://www.cnblogs.com/snowberg/archive/2012/06/17/2618921.html

设计模式笔记15:代理模式(Proxy Pattern)相关推荐

  1. Java24种设计模式(第二种)--代理模式(Proxy Pattern)

    Java24种设计模式 (第二种) 一.代理模式(Proxy Pattern) 模式逻辑: 什么是代理模式呢?我很忙,忙的没空理你,那你要找我呢就先找我的代理人吧,那代理人总要知道 被代理人能做哪些事 ...

  2. 设计模式——代理模式(Proxy Pattern)之为别人做嫁衣

    代理模式Proxy Pattern 代理模式 1.背景 2.定义 3.特征 4.应用场景 5.实验案例 参考 代理模式 1.背景 假如说我现在想租一间房子,虽然我可以自己去找房源,做卫生检测等一系列的 ...

  3. 设计模式-代理模式(Proxy Pattern)

    设计模式-代理模式(Proxy Pattern) 文章目录 设计模式-代理模式(Proxy Pattern) 一.定义 二.概念解释 三.场景 四.实现 1.类图 2.代码实现 五.小结 六.动态代理 ...

  4. 二十四种设计模式:代理模式(Proxy Pattern)

    代理模式(Proxy Pattern) 介绍 为其他对象提供一个代理以控制对这个对象的访问. 示例 有一个Message实体类,某对象对它的操作有Insert()和Get()方法,用一个代理来控制对这 ...

  5. 代理模式(Proxy Pattern)

    设计模式 - 吕震宇 .NET设计模式系列文章 薛敬明的专栏 乐在其中设计模式(C#) C#设计模式(13)-Proxy Pattern 一. 代理(Proxy)模式 代理(Proxy)模式给某一个对 ...

  6. 设计模式(结构型)之代理模式(Proxy Pattern)

    PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbob ...

  7. JAVA设计模式Design Pattern→单例模式Singleton Pattern、工厂模式Factory Pattern、代理模式Proxy Pattern

    私有化构造函数的类可以提供相应的 "接口"(一般就是静态方法)来返回自己的唯一实例供外部调用,像这样的确保只生成一个实例的模式被称作单例模式. 工厂模式,一个模型,用来大规模的生产 ...

  8. 27代理模式(Proxy Pattern)

    直接与间接:    人们对复杂的软件系统常有一种处理手法,即增加一层间接层,从而对系统获得一种更为灵活. 满足特定需求的解决方案.                                    ...

  9. 设计模式之略见一斑(代理模式Proxy)

    普通对象所需要完成的任务就是通过公共接口为外界提供自己所承诺的服务.然而,有时候合法的对象可能会因为各种原因而无法完成自己常规的任务.尤其是当对象需要长时候才能载入内存.对象正运行在另一台计算机上或者 ...

  10. [设计模式-结构型]代理模式(Proxy)

    概括 名称 Proxy 结构 动机 为其他对象提供一种代理以控制对这个对象的访问. 适用性 在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用P r o x y 模式.下面是一 些可以使用P ...

最新文章

  1. 老板用人5大原则,能力绝不是首选!大多数人的想法是错误的
  2. buu [BJDCTF 2nd]燕言燕语-y1ng
  3. 利用UDEV服务解决RAC ASM存储设备名
  4. 前端学习(3042):vue+element今日头条管理-用户退出
  5. android 对话框 图片,android – AlertDialog按钮的图像
  6. 比亚迪后续车都会搭在鸿蒙系统吗_华为鸿蒙系统上车,比亚迪汉发布!我告诉你华为鸿蒙到底是什么...
  7. 为什么程序员的女朋友或老婆颜值普遍都偏高?
  8. python 可视化 画直线_用Python画江苏省地图,实现各地级市数据可视化
  9. c语言结构体在内存中的存储,C语言结构体在内存中的存储情况探究------内存对齐...
  10. 一张图了解Spring Cloud微服务架构
  11. Linux下高速缓存DNS的配置
  12. 【数据库系统设计】DBMS的数据库保护
  13. 分治法 ——查找问题 —— 寻找两个等长有序序列的中位数
  14. [paper reading] DenseNet
  15. 基于Keras搭建mnist数据集训练识别的Pipeline
  16. php 伸展菜单代码,JQUERY编写的一款简易伸展显示详情菜单特效
  17. 如何从“人肉运维”升级为“智能运维”?
  18. ⭐算法入门⭐《广度优先搜索》中等01 —— LeetCode 994. 腐烂的橘子
  19. python神经网络编程 代码,python神经网络算法代码
  20. 如何才能够系统地学习Java并发技术?

热门文章

  1. S5PV210开发 -- 前言
  2. 记录一次Socket异常:java.net.SocketException: Connection reset
  3. Mysql:Mysql数据库系统表之详细了解INNODB_TRX、INNODB_LOCKs、INNODB_LOCK_waits、PROCESSLIST表
  4. 叶县有没有计算机培训学校,叶县中等专业学校
  5. Core Dump流程分析
  6. Algorithm, Secret key and Protocol
  7. kernel 3.10内核源码分析--内核栈及堆栈切换
  8. python 惰性_Django中的“惰性翻译”方法的相关使用
  9. android 隐藏webview地址栏,flutter - 在Flutter Webview中隐藏Url引用 - SO中文参考 - www.soinside.com...
  10. 2能不用cuda_cuda学习-1-cufft的使用