代理模式
代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。
在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式一般涉及到的角色
抽象角色:声明真实对象和代理对象的共同接口。
(为什么要有抽象角色?)因真实对象和代理对象可以实现相同的功能,但客户不能直接使用真实对象的功能,可通过代理对象的功能调用真是对象的功能,所以该功能(比如例子中的request())就在一个抽象类或者接口中声明。
代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能够代替真实对象。
同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
用实例来说明
首先是抽象角色类,可以定义一个接口或者抽象类:
/** * 真实对象和代理对象的共同接口 * */ public abstract class Subject { public abstract void request(); }
之后是真实角色的类,实现接口,并完成实际工作:
/** * 真实角色 */ public class RealSubject extends Subject { @Override public void request() { System.out.println("From Real Subject!"); } }
然后定义代理角色,内部包含对真实角色对象的引用,并且封装功能:
/** * 代理角色 * */ public class ProxySubject extends Subject { //代理角色对象内部含有对真实对象的引用 private RealSubject realSubject; @Override public void request() { //在真实角色操作之前所附加的操作 preRequest(); if(null == realSubject) { realSubject = new RealSubject(); } //真实角色所完成的事情 realSubject.request(); //在真实角色操作之后所附加的操作 postRequest(); } private void preRequest() { System.out.println("Pre Request."); } private void postRequest() { System.out.println("Post Request"); } }
在客户端进行调用时:
/** * 客户类 * */ public class Client { public static void main(String[] args) { Subject subject = new ProxySubject(); subject.request(); } }
由以上代码可以看出,客户实际需要调用的是RealSubject类的request()方法,现在用ProxySubject来代理RealSubject类,同样达到目的,同时还封装了其他的方法(preRequest(),postRequest()),可以处理一些其它问题。
问题
如果要按照上述的方式(静态代理)使用代理模式,那么真实角色必须是实现已经存在的,并将其作为代理对象的内部属性。
但是实际使用时,一个真实角色必须对应一个代理角色,但如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色,该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。
参考资料
圣思园张龙老师Java SE系列视频教程。
应用场景
现实世界中,秘书就相当于一个代理,老板开会,那么通知员工开会时间、布置会场、会后整理会场等等开会相关工作就可以交给秘书做,老板就只需要开会就行了,不需要亲自做那些事。同理,在我们程序设计中也可使用代理模式来将由一系列无关逻辑组合在一起的代码进行解耦合,比如业务代码中的日志代码就可以在代理中进行。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),这不难理解。复杂隐藏代理和外观模式是不一样的,因为代理控制访问,而外观模式是不一样的,因为代理控制访问,而外观模式只提供另一组接口。