一、模式动机
- 通过引入一个新的对象(如小图片和远程代理对象)来实现对真实对象的操作,或者将新的对象作为真实对象的一个替身
- 引入代理对象来间接访问一个对象
二、模式定义
- 给某一个对象提供一个代理,并由代理对象控制对原对象的引用
- 对象结构型模式
- 代理对象可以在客户端和目标对象之间起到中介的作用
- 通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外的新服务
模式分类
- 远程代理(Remote Proxy):为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以在同一台主机中,也可以在另一台主机中,远程代理又称为大使(Ambassador)
- 虚拟代理(Virtual Proxy):如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建
- 保护代理(Protect Proxy):控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限
- 缓冲代理(Cache Proxy):为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果
- 智能引用代理(Smart Reference Proxy):当一个对象被引用时,提供一些额外的操作,例如将对象被调用的次数记录下来等
三、模式结构
- Subject(抽象主题角色),声名接口,在需要使用真实主题时,都可以使用接口
- Proxy(代理角色),包含对真实主题的引用
- RealSubject(真实主题角色),包含真实的业务
四、案例实现
案例背景
在一个论坛中已注册用户和游客的权限不同,已注册的用户拥有发帖、修改自己的注册信息、修改自己的帖子等功能;而游客只能看到别人发的帖子,没有其他权限。使用代理模式来设计该权限管理模块。
在本实例中我们使用代理模式中的保护代理,该代理用于控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。
案例结构
代码实现
抽象主题
public interface AbstractPermission {
void modifyUserInfo();
void viewnote();
void publishnote();
void modifynote();
void setLevel(int level);
}
具体主题
public class RealPermission implements AbstractPermission{
@Override
public void modifyUserInfo() {
System.out.println("修改用户信息");
}
@Override
public void viewnote() {
}
@Override
public void publishnote() {
System.out.println("发布新帖");
}
@Override
public void modifynote() {
System.out.println("修改发帖内容");
}
@Override
public void setLevel(int level) {
}
}
代理
public class PermissionProxy implements AbstractPermission{
private RealPermission realPermission = new RealPermission();
private int level =0;
@Override
public void modifyUserInfo() {
if (0 == level){
System.out.println("对不起,您没有权限");
} else if (1 == level) {
realPermission.modifyUserInfo();
}
}
@Override
public void viewnote() {
System.out.println("查看帖子");
}
@Override
public void publishnote() {
if (0 == level){
System.out.println("对不起,您没有权限");
} else if (1 == level) {
realPermission.publishnote();
}
}
@Override
public void modifynote() {
if (0 == level){
System.out.println("对不起,您没有权限");
} else if (1 == level) {
realPermission.modifynote();
}
}
@Override
public void setLevel(int level) {
this.level = level;
}
}
客户测试
public class Client {
public static void main(String[] args) {
AbstractPermission permission = (AbstractPermission) XMLUtil.getBean();
permission.modifynote();
permission.viewnote();
permission.publishnote();
permission.modifynote();
System.out.println("-----------------");
permission.setLevel(1);
permission.modifyUserInfo();
permission.viewnote();
permission.publishnote();
permission.modifynote();
}
}
案例结果
案例分析
在代理中定义realPermission对象,用于调用真实业务,并进行权限判断,实现对权限的控制,0为游客,1为已注册用户
五、模式分析
抽象主题
public abstract class Subject {
public abstract void request();
}
具体主题
public class RealSubject extends Subject{
public void request() {
//业务方法具体实现代码
}
}
代理主题
public class Proxy extends Subject {
private RealSubject realSubject = new RealSubject();
//维持一个对真实主题对象的引用
public void preRequest() { …... }
public void request() {
preRequest();
realSubject.request(); //调用真实主题对象的方法
postRequest();
}
public void postRequest() { …… }
}
六、总结
模式优点
- 能够协调调用者和被调用者,在一定程度上降低了系统的耦合度
- 客户端可以针对抽象主题角色进行编程,增加和更换代理类无须修改源代码,符合开闭原则,系统具有较好的灵活性和可扩展性
模式缺点
- 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢(例如保护代理)
- 实现代理模式需要额外的工作,而且有些代理模式的实现过程较为复杂(例如远程代理)
使用情形
- 当客户端对象需要访问远程主机中的对象时可以使用远程代理
- 当需要用一个消耗资源较少的对象来代表一个消耗资源较多的对象,从而降低系统开销、缩短运行时间时可以使用虚拟代理
- 当需要为某一个被频繁访问的操作结果提供一个临时存储空间,以供多个客户端共享访问这些结果时可以使用缓冲代理
- 当需要控制对一个对象的访问,为不同用户提供不同级别的访问权限时可以使用保护代理
- 当需要为一个对象的访问(引用)提供一些额外的操作时可以使用智能引用代理