每天一个设计模式(8):代理模式
首先说下,本来写这个设计模式的系列,打算每天总结一个设计模式的,但是真的是太忙了(尤其是最近),导致现在的情况和本系列名字“每天一个设计模式”极不相符,真是尴尬啊,/(ㄒoㄒ)/~~
但是,最近在复习Spring的AOP的时候,涉及到了代理模式,所以,还是抽出时间把代理模式总结一下,由于现在时间真的是有限,故本文参考了一些优秀的博主的相关文章,文末给出了参考链接。
正文开始了:
一. 定义
代理模式为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。对一个对象进行访问控制的一个原因是为了只有在我们确实需要这个对象时才对它进行创建和初始化。它是给某一个对象提供一个替代者(占位者),使之在client对象和subject对象之间编码更有效率。
比如我们在租房子的时候回去找中介,因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。再如我们有的时候打官司,我们需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们的想法。
二. UML关系图
三. 模式的组成
代理模式中有三种角色:
1. 代理角色(Proxy)
代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
2. 抽象角色(Subject)
声明真实对象和代理对象的共同接口。
这样就在任何使用RealSubject的地方都可以使用Proxy。代理角色通过持有真实角色RealSubject的引用,不但可以控制RealSubject的创建或删除,可以在RealSubject被调用前进行拦截,或在调用后进行某些操作。
3. 真实角色(RealSubject)
代理角色所代表的真实对象,是我们最终要引用的对象。
四. 优缺点
优点
代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度。使用代理模式,可以将功能划分的更加清晰,有助于后期维护。
缺点
由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
五. 实现代码
1 //抽象对象角色 2 public abstract class AbstractObject { 3 //操作 4 public abstract void operation(); 5 }
1 //目标对象角色 2 public class RealObject extends AbstractObject { 3 @Override 4 public void operation() { 5 //一些操作 6 System.out.println("一些操作"); 7 } 8 }
1 //代理对象角色 2 public class ProxyObject extends AbstractObject{ 3 RealObject realObject = new RealObject(); 4 @Override 5 public void operation() { 6 //调用目标对象之前可以做相关操作 7 System.out.println("before"); 8 realObject.operation(); 9 //调用目标对象之后可以做相关操作 10 System.out.println("after"); 11 } 12 }
1 //客户端 2 public class Client { 3 4 public static void main(String[] args) { 5 // TODO Auto-generated method stub 6 AbstractObject obj = new ProxyObject(); 7 obj.operation(); 8 } 9 10 }
六. 应用场景
当我们需要使用的对象很复杂或者需要很长时间去构造,这时就可以使用代理模式(Proxy)。例如:如果构建一个对象很耗费时间和计算机资源,代理模式(Proxy)允许我们控制这种情况,直到我们需要使用实际的对象。一个代理(Proxy)通常包含和将要使用的对象同样的方法,一旦开始使用这个对象,这些方法将通过代理(Proxy)传递给实际的对象。 一些可以使用代理模式(Proxy)的情况:
- 一个对象,比如一幅很大的图像,需要载入的时间很长。
- 一个需要很长时间才可以完成的计算结果,并且需要在它计算过程中显示中间结果
- 一个存在于远程计算机上的对象,需要通过网络载入这个远程对象则需要很长时间,特别是在网络传输高峰期。
- 一个对象只有有限的访问权限,代理模式(Proxy)可以验证用户的权限
代理模式(Proxy)也可以被用来区别一个对象实例的请求和实际的访问,例如:在程序初始化过程中可能建立多个对象,但并不都是马上使用,代理模式(Proxy)可以载入需要的真正的对象。这是一个需要载入和显示一幅很大的图像的程序,当程序启动时,就必须确定要显示的图像,但是实际的图像只能在完全载入后才可以显示!这时我们就可以使用代理模式(Proxy)。
使用代理模式来将由一系列无关逻辑组合在一起的代码进行解耦合,比如业务代码中的日志代码就可以在代理中进行。spring的AOP就是典型的动态代理应用。
七. 动态代理
动态代理之所以被称为动态,是因为运行时才将它的类创建出来。代码开始执行时,还没有proxy类,它是根据需要从你传入的接口集创建的。Proxy本身是利用静态的Proxy.newProxyInstance()方法在运行时动态地创建的。代理类有一个静态方法isProxyClass(),此方法的返回值如果为true,表示这是 一个动态代理类。
动态代理的UML关系图如下:
可以把InvocationHandler想成是代理收到方法调用后,请求做实际工作的对象。其中只有一个invoke()方法,不管代理被调用的是何种方法,处理器被调用的一定是invoke()方法。
八. 代理模式的应用形式
- 远程代理(Remote Proxy) -可以隐藏一个对象存在于不同地址空间的事实。也使得客户端可以访问在远程机器上的对象,远程机器可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。
- 虚拟代理(Virtual Proxy) – 允许内存开销较大的对象在需要的时候创建。只有我们真正需要这个对象的时候才创建。
- 写入时复制代理(Copy-On-Write Proxy) – 用来控制对象的复制,方法是延迟对象的复制,直到客户真的需要为止。是虚拟代理的一个变体。
- 保护代理(Protection (Access)Proxy) – 为不同的客户提供不同级别的目标对象访问权限
- 缓存代理(Cache Proxy) – 为开销大的运算结果提供暂时存储,它允许多个客户共享结果,以减少计算或网络延迟。
- 防火墙代理(Firewall Proxy) – 控制网络资源的访问,保护主题免于恶意客户的侵害。
- 同步代理(SynchronizationProxy) – 在多线程的情况下为主题提供安全的访问。
- 智能引用代理(Smart ReferenceProxy) - 当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。
- 复杂隐藏代理(Complexity HidingProxy) – 用来隐藏一个类的复杂集合的复杂度,并进行访问控制。有时候也称为外观代理(Façade Proxy),这不难理解。复杂隐藏代理和外观模式是不一样的,因为代理控制访问,而外观模式是不一样的,因为代理控制访问,而外观模式只提供另一组接口。
参考:http://blog.csdn.net/jackiehff/article/details/8621517
http://www.cnblogs.com/java-my-life/archive/2012/04/23/2466712.html
http://www.cnblogs.com/mengdd/archive/2013/05/07/3065619.html
http://blog.csdn.net/zhangerqing/article/details/8239539