目录
本文的结构如下:
- 引言
- 什么是代理模式
- 模式的结构
- 典型代码
- 代理模式分类
- 代码示例
- 代理模式和装饰者模式的区别
- 静态代理和动态代理的区别
- 优点和缺点
- 适用环境
- 模式应用
一、引言
说到明星,大家都知道一般明星都有经纪人,很多时候要拍个广告,参加个节目,都不是直接联系明星本人,都是先打电话到经纪人这里,然后再由经纪人转告给某个明星,这里面,经纪人起到了一个代理的作用;还有平常说的租房中介,也替房主起了代理的作用…
在软件开发中,也有这种类似的情况。由于某些原因,客户端不想或不能直接访问一个对象,此时可以通过一个称之为“代理”的第三者(就像经纪人和中介)来实现间接访问,这就是代理模式。
二、什么是代理模式
代理模式使用代理对象完成用户请求,屏蔽用户对真实对象的访问。现实世界的代理人被授权执行当事人的一些事宜,无需当事人出面,从第三方的角度看,似乎当事人并不存在,因为他只和代理人通信。而事实上代理人是要有当事人的授权,并且在核心问题上还需要请示当事人。
代理模式的定义:
代理模式(Proxy Pattern):给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。代理模式是一种对象结构型模式。
在软件设计中,使用代理模式的意图也很多,比如因为安全原因需要屏蔽客户端直接访问真实对象,或者在远程调用中需要使用代理类处理远程方法调用的技术细节 (如 RMI),也可能为了提升系统性能,对真实对象进行封装,从而达到延迟加载的目的。
三、模式的结构
代理模式的UML类图如下:
代理模式的结构比较简单,包含如下三个角色:
- Subject(抽象主题角色):它声明了真实主题和代理主题的共同接口,这样一来在任何使用真实主题的地方都可以使用代理主题,客户端通常需要针对抽象主题角色进行编程。
- Proxy(代理主题角色):它包含了对真实主题的引用,从而可以在任何时候操作真实主题对象;在代理主题角色中提供一个与真实主题角色相同的接口,以便在任何时候都可以替代真实主题;代理主题角色还可以控制对真实主题的使用,负责在需要的时候创建和删除真实主题对象,并对真实主题对象的使用加以约束。通常,在代理主题角色中,客户端在调用所引用的真实主题操作之前或之后还需要执行其他操作,而不仅仅是单纯调用真实主题对象中的操作。
- RealSubject(真实主题角色):它定义了代理角色所代表的真实对象,在真实主题角色中实现了真实的业务操作,客户端可以通过代理主题角色间接调用真实主题角色中定义的操作。
四、典型代码
代理模式的结构图比较简单,但是在真实的使用和实现过程中要复杂很多,而且它有很多变化。
抽象主题类声明了真实主题类和代理类的公共方法,它可以是接口、抽象类或具体类,客户端针对抽象主题类编程,一致性地对待真实主题和代理主题,典型的抽象主题类代码如下:
public interface Subject {
void request();
}
真实主题代码:
public class RealSubject implements Subject {
public void request() {
// todo
}
}
代理类代码:
public class Proxy implements Subject {
private RealSubject realSubject = new RealSubject();//真实主题的引用
public void request() {
postRequest();
realSubject.request();
postRequest();
}
public void preRequest(){
//todo
}
public void postRequest(){
//todo
}
}
五、代理模式分类
在实际开发过程中,代理类的实现比上述代码要复杂很多,代理模式根据其目的和实现方式不同可分为很多种类,其中常用的几种代理模式简要说明如下:
- 远程代理(Remote Proxy):为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又称为大使(Ambassador)。
- 虚拟代理(Virtual Proxy):如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。
- 保护代理(Protect Proxy):控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。
- 缓冲代理(Cache Proxy):为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。
- 智能引用代理(Smart Reference Proxy):当一个对象被引用时,提供一些额外的操作,例如将对象被调用的次数记录下来等。
六、代码示例
6.1、远程代理
说到远程代理,就需要先了解RMI(Remote Method Invocation),如果有不知道的,可以查下资料了解下。这里也顺便帖一个链接,关于简单介绍RMI实现原理的。
stub 和 skeleton 的讲解,自己实现一个stub和skeleton程序。
简单说,RMI是用Java所特有的分布式计算技术,它允许运行在一个Java虚拟机上的对象调用运行在另一个Java虚拟机上的对象的方法,从而使Java编程人员可以方便地在网络环境中作分布式计算。
利用RMI进行编程就是一个典型的远程代理,这里套用网络上的一张图来大概说明其原理: