问题:
在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
•当由于某些特定的需要调用的对象在另外一台机器上,需要跨越网络才能访问,在没有WebService的情况下我们需要直接coding去处理网络连接、处理打包、解包等等非常复杂的步骤,而WebService的出现帮我们解决了其中的一些问题简化客户端的处理,我们只需在客户端建立一个远程对象的代理,客户端就象调用本地对象一样调用该代理,再由代理去跟实际对象联系,对于客户端来说可能根本没有感觉到调用的东西在网络另外一端。
定义:
对其他对象提供一种代理以控制对这个对象的访问。
意图:
提供一个Subject角色,它定义了Proxy与ConcreteSubject的功用接口,使得任何使用ConcreteSubject的地方都能使用Proxy,Proxy对象维护了一个对ConcreteSubject对象的引用,Proxy接受来至客户端请求,通过这个引用,将请求转给具体的ConcreteSubject对象,Proxy在执行具体对象操作时可以附加其他的操作。这样通过增加代理来解耦客户端与调用对象之间的调用,封装了原来客户端调用具体对象的一些相关细节,客户端不在依赖具体的调用对象,具体对象的修改对客户端来说是透明的,不会影响客户端的修改。
参与者:
•抽象主题(Subject)角色:
声明了代理主题和具体主题的公共接口,使任何需要具体主题的地方都能用代理主题代替。
•代理主题(Proxy)角色:
代理对象角色内部含有对具体对象的引用,从而可以操作具体对象,同时代理对象提供与具体对象相同的接口以便在任何时刻都能代替具体对象。同时,代理对象可以在执行具体对象操作时,附加其他的操作,相当于对具体对象进行封装。
•具体具体对象(ConcreteSubject)角色:
代理角色所代表的具体对象,是我们最终要引用的对象。
UML:
实例代码:
/// 抽象主题(Subject)角色
/// </summary>
public interface ISubject
{
void Request();
}
/// <summary>
/// 具体具体对象(ConcreteSubject)角色
/// </summary>
public class ConcreteSubject : ISubject
{
public void Request()
{
System.Console.WriteLine("运行具体真实对象!");
}
}
/// <summary>
/// 代理主题(Proxy)角色
/// </summary>
public class ProxySubject : ISubject
{
/// <summary>
/// 一个Subject的引用
/// </summary>
ISubject subject = new ConcreteSubject();
public void Request()
{
System.Console.WriteLine("开始请求真实对象!");
//通过引用请求ConcreteSubject
subject.Request();
System.Console.WriteLine("结束请求真实对象!");
}
}
/// <summary>
/// 客户端测试
/// </summary>
void ProxyTest()
{
ProxySubject pr = ProxySubject();
pr.Request();
}
分类适用场合:
•远程代理,也就是为了一个对象在不同的地址空间提供局部代表,这样可以隐藏一个对象存在于不同地址空间的事实,就像web service里的代理类一样。
•虚拟代理,根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象,比如浏览器的渲染的时候先显示问题,而图片可以慢慢显示(就是通过虚拟代理代替了真实的图片,此时虚拟代理保存了真实图片的路径和尺寸。
•安全代理,用来控制真实对象访问时的权限,一般用于对象应该有不同的访问权限。
•智能指引,只当调用真实的对象时,代理处理另外一些事情。例如C#里的垃圾回收,使用对象的时候会有引用次数,如果对象没有引用了,GC就可以回收它了。
代理模式与外观模式的区别:
•外观模式也是屏蔽复杂性的,但是外观模式不会实现客户端调用的目标类型接口。
•一般客户端调用外观模式的方法都是直接调用。
•代理模式中对客户端目标对象类型抽象接口具体化了。
•外观模式是代理模式中一种特殊的子级模式(广泛的,非约束性)。
总结:
代理模式非常常用,大致的思想就是通过为对象加一个代理来降低对象的使用复杂度、或是提升对象使用的友好度、或是提高对象使用的效率。
GoF《设计模式》中说的:为其他对象提供一种代理以控制这个对象的访问。理类型从某种角度上讲也可以起到控制被代理类型的访问的作用。