设计模式-代理模式

最后更新于:2022-04-01 20:25:31

### 一、上篇回顾 很久没有更新设计模式系列的文章了,有了很多热心朋友的反馈,我决定继续将这个系列赶快写完,最近由于过年了,有很多相关的事宜要做,所以没有时间来写,也是对大家的说下抱歉,感觉写文章的时间越来越少了,不过我会努力,尽快将这个系列写完,与大家共勉,希望大家有什么意见或建议,都可以帮我提出来,我好改进,谢谢!。 本文主要是讲述设计模式中的结构性模式中的最后一个本系列讲述的模式,也是经常用到的模式,代理模式,由于目前我们在很多的技术中都会用到 这个代理模式,所以对我们来说,代理模式是必须掌握的模式之一。我们先来看看代理的思路及原理: [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b3ed742.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201353379425.png) 通过上面的图片,我们可以看到,通过增加代理来解耦A与C之间的调用,这样可以封装原来C调用A的一些相关细节,转换成C直接调用B中封装后 的代理方法,则等同于访问A。对于WebService的远程调用时,如果我们使用添加Web引用的方式,那么WebService会为我们自动生成代理类的,这个我这里就不演示了,包括Castle中的AOP等实现方案都是基于动态代理的机制来实现,当然思路都是这样的,WCF中也有用到代理的思想。 ### 二、摘要 前面我们讲述了外观模式中的关于动态代理中的一些实现,当然代理模式与外观模式的侧重点还是有所不同,外观模式是将众多细粒度的功能,封 装成一个粗粒度的功能,供客户应用程序使用。而代理模式,为其他对象提供一个代理类,通过该代理类来完成目标对象的访问,代理模式相对外观模式来说,关键不同是在内部,外观我们知道是将细粒度的功能进行简单封装,而代理模式则是内部实现很复杂,其复杂性主要体现在来自如下的几类复杂性: [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b420bbf.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201353489906.png) 可能上述的复杂性还不完整,例如还可能有目前的比较新兴的大数据量的虚拟代理或者是智能代理,这方面由于自身不足,所以还无法讲述。 本文将会结合举例说明上述的几类代理的复杂性的简单说明,希望能说明清楚。 ### 三、本文大纲 a、上篇回顾。 b、摘要。 c、本文大纲。 d、代理模式的特点及使用场景。 e、代理模式的经典实现。 f、代理模式的其他方案。 g、代理模式使用总结。 h、系列进度。 i、下篇预告。 ### 四、代理模式的特点及使用场景 我们先来看看代理模式的特点及使用场景吧,我们先来看看一个简单的场景吧: 我们现在要构建一个分布式应用程序,那么一般在.NET平台下,我们一般会采用WCF或者WebService的方式来发布应用,不管是平时大家听说的SOA架构的实现,还是其他的ESB总线架构等,也无非是二种实现方式,一种是通过API接口编程来实现,通过WCF的Remoting或者是其他的方式来调用远程服务,另一种是通过WebService的形式来发布服务,那么既然有了发布服务之后,那么我们之后的操作可能更多关心的是,如果在客户端使用 这个服务,那么一般我们可能采用的最常用的方式,就是在客户端由平台自动生成一个代理或者我们自己写一个代理类,当然这个代理类可以是通用的代理类或者是为某些服务单独写代理,能够更方便的使用及提升效率等。 通过上面的说明,那么我们现在基本上知道了,代理模式的作用体现在哪里,下面我们来详细展开说明吧;当我们的一个服务写的很复杂,但是我们在客户端调用的时候,我们又不希望在客户端使用起来太复杂,这个时候,可能我们想我们通过使用代理类,那么通过代理类,这个客户端与远程的服务类进行交互过程就变成客户端与代理类的交互,那么给客户的感觉就像服务类就在本地一样,这样不但降低了复杂性,而且也降低了耦合性。 那么一般代理类有什么要求呢?一般来说代理对象必须实现目标对象定义的一些接口,只有这样,客户端应用程序在使用的时候,通过接口调用来访问目标对象的服务,否则就等于引入复杂度,反而没有解决问题。 使用代理的目的是控制客户端程序访问目标对象,因此代理必须知道目标对象的类型及目标对象在哪里,如何访问等都必须明确。 代理对象有的时候也可以是抽象类型,这样目标类型就可以是未确定的,我们可以通过创建型模式来动态的创建目标对象,当然前提是这些目标对象是代理对象类型。 代理模式的类图 ![](image/56a5c105910ac.jpg) ### 五、代理模式的经典实现 下面给出代理模式的经典实现: 我们以如下场景为例,我们现在要实现一个MP3播放的相关功能,一般来说有很多的音频文件; 下面我们来看看如何使用代理模式来实现。 (1)、定义客户端调用的具体的音乐媒体类型类型 [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b439805.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201353507723.png) (2)、定义客户端调用的目标对象的接口 [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b44ec0d.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201353523904.png) (3)、定义具体的目标类型的实现 [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b461665.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201353572329.png) (4)、定义代理类,该代理类实现了目标类型的接口。 [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b47b95c.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354023437.png) (5)、具体的客户端调用 [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b491a9a.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354042093.png) 上面基本上给出了一个简单的例子说明,当然具体的代理模式的思路就是这样了,当然参考上面的类图来做的话,和我的这个形式差不多,具体的 思想就是为目标类型定义一个接口,然后代理类实现该接口,那么在代理类中指定具体的目标类型的调用,完成目标类型的调用,返回调用后的结果,那么就等于代理类封装了目标类型的调用。 ### 六、代理模式的其他实现方案 上面我们给出了代理模式的经典实现方案,那么我们本节看看其他的实现方案,来扩展下我们的方案的使用场景及一些其他的应用场景的情况: 我们给出WebService的示例过程吧: (1)、 为了说明我们给出的示例过程,我们来新建一个ASP.NET WEB应用程序网站,添加一个WebService服务文件。 [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b4aabc6.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354114431.png) (2)、 选择添加一个WebService文件 [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b4cc285.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/2011022013541565.png) (3)、添加完后,修改HelloWord方法,添加一个name字段,代表输入字符串,输出相应的代码 [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b4e38ed.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354183115.png) (4)、添加完毕后,在浏览器中查看 [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b50f158.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354241125.png) (5)、测试,是否服务正确。运行后的结果应该如下: [  ![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b5446a3.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354306005.png) 置于其他的相应的信息我就补贴出来了,然后我们将webservice服务发布出来,通过二种形式来添加代理 1、通过web引用的形式: (1)、先找到webservice服务的发布地址 [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b5636c0.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354378343.png) (2)、复制地址,并且在要引用该webservice服务的项目中在引用文件夹中点击右键 [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b580c13.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354415339.png) (3)、将复制的地址,输入到服务引用的地址栏中 [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b59729e.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354465683.png) (4)、点击前往,系统就会自动与webservice建立测试连接。 [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b5b0338.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354539691.png) 如果没有出现上述的服务内容,那么则可能服务没有发布,或者服务的引用添加的路径不对等。点击确定,这个时候,我们来看看代理文件生成的内容: [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b5cf7d9.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201355073188.png) 我们来看看系统为我们自动生成的WEB服务代理的代码吧: 通过reflactor中的对象浏览器来查看系统生成的内容吧: [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b5eab4d.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201355116696.png) 具体的代码太多了,我这里就不贴出了,大家可以看看,我这里给出解析webservice的一些通用的统一代理代码。 [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b615596.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201355165578.png) [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b630075.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201355207624.png) 这样就完成通用的Get请求的方式来调用webservice服务。 ### 七、代理模式使用总结 通过上面的webservice的讲述,我想大家对代理模式还是会有些陌生,其实代理模式我们前面也说道,代理是将目标对象的复杂性进行封装,通过代理来完成调用,那么我们针对前面的客户端调用的目标类型的接口定义,并且目标对象要实现这个接口,代理类也要实现这个接口。 下面来总结下代理模式与外观模式的区别: 1、外观模式也是屏蔽复杂性的,但是外观模式不会实现客户端调用的目标类型接口。 2、一般客户端调用外观模式的方法都是直接调用。 3、代理模式中对客户端目标对象类型抽象接口具体化了。 4、外观模式是代理模式中一种特殊的子级模式(广泛的,非约束性)。 针对前面我们提到过,代理模式中还有将代理类定义成抽象类型,然后完成动态的调用的情况,那么我们看看我们如何来组织呢? 1、定义多个播放文件格式对象 [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b64e1f0.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201355248930.png) 新增加上述的3个文件 2、修改playProxy的代码如下: [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b6658be.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201355285370.png) 3、具体的代理代码如下:这里参考AOP的实现机制 [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b68568e.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201355331004.png) 4、具体的调用代码如下: [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b696934.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201355348331.png) 当然这里的具体的调用过程还有很多方法可以进行改进的更好,比如在内部的枚举模式,修改成创建工厂的形式来完成对象的动态创建及调用等。我这里就 不进行优化了,只是展示出思路和方案,希望大家提出不同的意见! ### 八、系列进度 创建型 1、[系统架构技能之设计模式-单件模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/10/02/1841390.html) 2、[系统架构技能之设计模式-工厂模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/11/30/1892227.html) 3、[系统架构技能之设计模式-抽象工厂模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/01/1893388.html) 4、[系统架构技能之设计模式-创建者模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/02/1894771.html) 5、[系统架构技能之设计模式-原型模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/04/1896471.html) 结构型 1、[系统架构技能之设计模式-组合模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/06/1898161.html#commentform) 2、[系统架构技能之设计模式-外观模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/06/1897398.html) 3、[系统架构技能之设计模式-适配器模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/09/1901040.html) 4、[系统架构技能之设计模式-桥模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/10/1902185.html) 5、[系统架构技能之设计模式-装饰模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/11/1903392.html) 6、[系统架构技能之设计模式-享元模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/12/1903728.html) 7、系统架构技能之设计模式-代理模式 行为型 1、系统架构技能之设计模式-命令模式 2、系统架构技能之设计模式-观察者模式 3、系统架构技能之设计模式-策略模式 4、系统架构技能之设计模式-职责模式 5、系统架构技能之设计模式-模板模式 6、系统架构技能之设计模式-中介者模式 7、系统架构技能之设计模式-解释器模式 ### 九、下篇预告 下一篇我们将开始讲述行为型模式中的“命令模式”该模式是比较常用的模式,也是大众化的模式,希望能给大家说明清楚,对我自身来说也是一个不小的挑战,欢迎大家拍砖。
';