大话设计模式之代理模式
1、基本概念
随着互联网飞速的发展,现在许多软件系统都提供跨网络和系统的应用,但在跨网络和系统应用时,作为系统开发者并不希望客户直接访问系统中的对象。其中原因很多考虑到系统安全和性能因素,这时候聪明的开发者想到了在客户端和系统端添加一层中间层----代理层,也是即将要介绍的代理模式
(1)定义
代理模式(Proxy)为另一个对象提供一个替身或占位符以控制对这个对象的访问,简而言之就是用一个对象来代表另一个对象
(2)意图
提供其他对象一个代理或占位符,来控制该对象的访问权限。
(3)动机
为什么我们要控制对象的访问权限呢?其中一个原因是通过控制来延迟对象的创建和实例化,直到真正需要使用该对象才进行创建和实例化。由于一些对象创建和实例化需要占用大量系统资源,但我们并不能确定用户一定会调用该对象,所以通过延迟对象实例化来减缓系统资源的消耗。例如文档编辑器如word,我们可以在里面插入链接、图片等,但是并不是我们每次打开word时都有创建和实例化这些对象,特别是实例化图片对象很消耗资源,而且我们有必要实例化所有图片吗?当我们在查看word时,只是看到其中的一部分,所以没有必要实例化所以资源,当我们看下一页时再实例化也不迟。
(4)结构图
2、实例代码
软件系统设计可以提供本地或远程的方法,随着互联网的发展特别是WebService技术的提出,使得更多软件系统都提供远程方法调用。当我们访问网络上一台计算机的资源时,我们正在跨越网络障碍,跨越网络障碍有时候是非常复杂,因为要确保数据安全可靠地传输。如果真的要我们都去解决那些复杂网络问题,那么我估计程序员们疯了。还好代理模式(Proxy)帮我们解决了其中的一些问题----WebService技术。
现在让我们通过一个简单的加减乘除程序为例,说明什么是代理模式(Proxy)和如何实现。
现在我们服务器端提供计算方法,分别定义计算类Math和代理类MathProxy。然后我们的客户端通过调研MathProxy来间接用Math类的计算方法。
(1)定义加减的接口
public interface IMath { double add(double x, double y); double sub(double x, double y); }
(2)定义加减实体类
public class Math :IMath { public double add(double x,double y) { return x + y; } public double sub(double x,double y) { return x - y; } }
(3)定义加减代理类
public class MathProxy:IMath { private IMath math; public MathProxy(IMath math) { this.math = math; } public double add(double x,double y) { return math.add(x, y); } public double sub(double x,double y) { return math.sub(x, y); } }
(4)客户端代码
class Program { static void Main(string[] args) { IMath math = new Math(); MathProxy proxy = new MathProxy(math); double r1=proxy.add(1, 2); double r2 = proxy.sub(5, 6); Console.WriteLine(r1+r2); Console.ReadLine(); } }
3、总结
代理模式(Proxy)根据种类不同,效果也不尽相同:
- 远程(Remote)代理:为一个位于不同的地址空间的对象提供一个局域代表对象。这个不同的地址空间可以是在本机器中,也可是在另一台机器中。远程代理又叫做大使(Ambassador)。好处是系统可以将网络的细节隐藏起来,使得客户端不必考虑网络的存在。客户完全可以认为被代理的对象是局域的而不是远程的,而代理对象承担了大部份的网络通讯工作。由于客户可能没有意识到会启动一个耗费时间的远程调用,因此客户没有必要的思想准备。
- 虚拟(Virtual)代理(图片延迟加载的例子):根据需要创建一个资源消耗较大的对象,使得此对象只在需要时才会被真正创建。使用虚拟代理模式的好处就是代理对象可以在必要的时候才将被代理的对象加载;代理可以对加载的过程加以必要的优化。当一个模块的加载十分耗费资源的情况下,虚拟代理的好处就非常明显。
- Copy-on-Write代理:虚拟代理的一种。把复制(克隆)拖延到只有在客户端需要时,才真正采取行动。
- 智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。
代理模式(Proxy)VS 装饰者(Decorator)
意图:它们都提供间接访问对象层,都保存被调用对象的引用。
代理模式(Proxy):为另一个对象提供一个替身或占位符以控制对这个对象的访问,简而言之就是用一个对象来代表另一个对象。
装饰者(Decorator):动态地给一个对象添加一些额外的职责,就增加功能来说,Decorator模式比生成子类更为灵活,它避免了类爆炸问题,像装饰者(Decorator),代理模式(Proxy)组成一个对象并提供相同的接口,但代理模式并不关心对象动态职能的增减。
在代理模式(Proxy)中Subject定义了主要的功能,而且Proxy根据Subject提供功能控制对象的访问权限。在装饰者(Decorator)中Component只是提供了其中的一些功能,需要通过装饰链动态给对象增加职能。