适用环境:
远程代理:为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台主机中,也可以是在另一台主机中。远程代理又叫做大使(Ambasssador)。RMI(Remote Method Invocation 远程方法调用)、Web Service的实现原理。
虚拟代理:如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。
Copy-on-Write代理:它是虚拟代理的一种,把复制操作延迟到只有在客户端真正需要时才执行。
保护代理:控制对一个对象的访问,可以给不同用户提供不同级别的使用权限。
缓冲(Cache)代理:微末一个目标操作的结果提供临时的存储空间,以便于多个客户端可以共享这些结果。
防火墙(FireWall)代理:保护目标不让恶意用户接近。
同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。
智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,如将此对象被调用的次数记录下来等。
在这些种类的代理中,虚拟代理、远程代理和保护代理是常见的代理模式。不同类型的代理模式有不同的缺点,它们应用于不同的场合。
Spring框架中的AOP技术也是代理模式的应用,在Spring AOP中应用了动态代理(Dynamic Proxy)技术。
现实生活中如婚介所就是所谓的代理结构,当你忙于其他事情没有心思去找对象时,可以去找这样的代理机构来间接的帮你找到。
当直接访问某些对象存在问题时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,所访问的真实对象与代理对象需要事先同样的接口。所谓代理,就是一个人或者一饿机构代表另一个人或者另一个结构采取行动。通过引入代理对象来间接访问一个对象,这就是代理模式的模式动机。
定义:给某一个对象提供一个代理,并由代理对象控制原对象的引用。
模式结构图:
权限代理代码实现:
客户端:
package com.proxypattern.hing; public class Client { public static void main(String[] args) { //注意,客户端不会出现真正要代理的对象,因为该对象已经在代理类中有实例,这样可以避免要代理对象内部信息的泄露 AbstractPermission proxy = (AbstractPermission)XMLUtil.getBean(); proxy.modifyUserInfo(); proxy.setLevel(1); proxy.modifyUserInfo(); } }
抽象权限管理类:
package com.proxypattern.hing; //抽象权限类 public interface AbstractPermission { public void modifyUserInfo(); public void viewNote(); public void publishNote(); public void modifyNote(); public void setLevel(int level); }
真实权限管理类:
package com.proxypattern.hing; //真正的权限类 public class RealPermission implements AbstractPermission { @Override public void modifyUserInfo() { System.out.println("修改用户信息!"); } @Override public void viewNote() { // TODO Auto-generated method stub } @Override public void publishNote() { System.out.println("发表新帖"); } @Override public void modifyNote() { System.out.println("修改新帖"); } @Override public void setLevel(int level) { } }
代理权限管理类:
package com.proxypattern.hing; //代理的权限类 public class ProxyPermission implements AbstractPermission { private RealPermission rp = new RealPermission(); private int level = 0; @Override public void modifyUserInfo() { if(level == 0) { System.out.println("对不起,你没有访问权限"); }else { rp.modifyUserInfo(); } } @Override public void viewNote() { rp.viewNote(); } @Override public void publishNote() { rp.publishNote(); } @Override public void modifyNote() { if (level == 0) { System.out.println("对不起,你没有该权限"); }else { rp.modifyNote(); } } @Override public void setLevel(int level) { this.level = level; } }
总结:代理是将真正的主题角色封装到了代理主题角色中,通过相应控制调用真正的主题角色中的内容,而他们必须实现相同的接口,这样会使得客户端使用具有透明性。值得注意的是,此处已经将真实的主题角色设为了private保证了安全性。
代理模式和装饰模式:看起来这两个模式是有较多相似的地方的,但实际上使用代理模式时,代理对象和真实对象之间的关系通常在编译时就已经确定了,而装饰者则能够在运行时递归地被构造。