欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

设计模式-结构型-代理模式

程序员文章站 2022-04-14 23:30:53
代理模式(Proxy): 代理模式就是给某一个对象提供一个代理,并由代理对象控制对原有对象的引用。在一些情况下,一个客户不想或者不能直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。例如windows桌面端的快捷方式就是一个代理。 代理模式按照使用目的可以分为: 1)远程代理:为 ......

代理模式(proxy):

  代理模式就是给某一个对象提供一个代理,并由代理对象控制对原有对象的引用。在一些情况下,一个客户不想或者不能直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。例如windows桌面端的快捷方式就是一个代理。

代理模式按照使用目的可以分为:

  1)远程代理:为一个位于不同的地址空间的对象提供一个局域代表对象。这个不同的地址空间可以是本电脑中,也可以在另一台电脑中。如客户端调用web服务或wcf服务。

  2)虚拟代理:根据需要创建一个资源消耗较大的对象,使得对象只在需要时才会被真正创建。

  3)copy-on-write代理:虚拟代理的一种,把复制(或克隆)拖延到只有在客户端需要时,才真正采取行动。

  4)保护(protected or access)代理:控制一个对象的访问,可以给不同的用户提供不同级别的使用权限。

  5)cache代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以操作这些结果。

  6)防火墙(firewall)代理:保护目标不让恶意用户接近。

  7)同步化(synchronization)代理

  8)智能引用(smart reference)代理:当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来。

接下来以一个需求案例来说明下代理模式:

  现有收费商务信息查询系统的二次开发,增加需求:

    1)添加用户身份验证;2)添加日志记录;3)要求以松耦合的方式进行功能添加

    设计模式-结构型-代理模式 

  1 internal class program
  2 {
  3     private static void main(string[] args)
  4     {
  5         /*
  6          * <?xml version="1.0" encoding="utf-8" ?>
  7          * <configuration>
  8          *  <appsettings>
  9          *      <add key="proxy" value="proxy,proxy.proxysearcher" />
 10          *  </appsettings>
 11          * </configuration>
 12          */
 13         var proxy = configurationmanager.appsettings["proxy"].split(",");
 14         var searcher = (searcher)assembly.load(proxy[0]).createinstance(proxy[1]);
 15         var result = searcher.dosearch("杨过", "玉女心经");
 16     }
 17 }
 18 
 19 /// <summary>
 20 /// (1) accessvalidator:身份验证类,业务类,它提供方法validate()来实现身份验证。
 21 /// </summary>
 22 internal class accessvalidator
 23 {
 24     //模拟实现登录验证
 25     public bool validate(string userid)
 26     {
 27         console.writeline($"在数据库中验证用户{userid}是否是合法用户?");
 28         if (userid.equals("杨过"))
 29         {
 30             console.writeline("'{0}'登录成功!", userid);
 31             return true;
 32         }
 33         else
 34         {
 35             console.writeline("'{0}'登录失败!", userid);
 36             return false;
 37         }
 38     }
 39 }
 40 
 41 /// <summary>
 42 /// (2) logger:日志记录类,业务类,它提供方法log()来保存日志。
 43 /// </summary>
 44 internal class logger
 45 {
 46     //模拟实现日志记录
 47     public void log(string userid)
 48     {
 49         console.writeline($"更新数据库,用户{userid}查询次数加1!");
 50     }
 51 }
 52 
 53 /// <summary>
 54 /// (3) searcher:抽象查询类,充当抽象主题角色,它声明了dosearch()方法。
 55 /// </summary>
 56 internal interface searcher
 57 {
 58     string dosearch(string userid, string keyword);
 59 }
 60 
 61 /// <summary>
 62 /// (4) realsearcher:具体查询类,充当真实主题角色,它实现查询功能,提供方法dosearch()来查询信息。
 63 /// </summary>
 64 internal class realsearcher : searcher
 65 {
 66     public string dosearch(string userid, string keyword)
 67     {
 68         console.writeline($"用户{userid}使用关键词{keyword}查询商务信息!");
 69         return "返回具体内容";
 70     }
 71 }
 72 
 73 /// <summary>
 74 /// (5) proxysearcher:代理查询类,充当代理主题角色,它是查询代理,维持了对realsearcher对象、accessvalidator对象和logger对象的引用。
 75 /// </summary>
 76 internal class proxysearcher : searcher
 77 {
 78     private searcher searcher;
 79     private accessvalidator validator;
 80     private logger logger;
 81 
 82     public proxysearcher()
 83     {
 84         searcher = new realsearcher();
 85     }
 86 
 87     public string dosearch(string userid, string keyword)
 88     {
 89         //如果身份验证成功,则执行查询
 90         if (this.validate(userid))
 91         {
 92             string result = searcher.dosearch(userid, keyword); //调用真实主题对象的查询方法
 93             this.log(userid); //记录查询日志
 94             return result; //返回查询结果
 95         }
 96         else
 97         {
 98             return null;
 99         }
100     }
101 
102     //创建访问验证对象并调用其validate()方法实现身份验证
103     public bool validate(string userid)
104     {
105         validator = new accessvalidator();
106         return validator.validate(userid);
107     }
108 
109     //创建日志记录对象并调用其log()方法实现日志记录
110     public void log(string userid)
111     {
112         logger = new logger();
113         logger.log(userid);
114     }
115 }

  代理模式角色分四种:

    1)主题接口(searcher):定义代理类和真实主题的公共对外方法,也是代理类代理真实主题的方法;

    2)真实主题(realseracher):真正实现业务逻辑的类;

    3)代理类(proxyseracher):用来代理和封装真实主题;

    4)客户端:使用代理类和主题完成工作。

代理模式的优缺点:

  优点:

    1)代理模式能够将调用用于真正被调用的对象隔离,在一定程度上降低了系统的耦合度;

    2)代理对象在客户端和目标对象之间起到一个中介的作用,这样可以起到对目标对象的保护。代理对象可以在对目标对象发出请求之前进行一个额外的操作,例如权限检查等。

  缺点:

    1)由于在客户端和真实主题之间增加了一个代理对象,所以会造成请求的处理速度变慢;

    2)实现代理类也需要额外的工作,从而增加了系统的实现复杂度。

代理模式与的区别?

  学习完适配器模式和代理模式之后,会产生这样的疑问:貌似两种模式差不多?两者都是定义了一个目标对象(抽象对象),客户端依赖该抽象对象完成相应功能,这么一解释好像是一样的,那为什么大牛们会分成两种模式呢?适配器模式是因为新旧接口不一致导致出现了客户端无法得到满足的问题,但由于旧的接口是不能被完全重构掉的,因为我们还想使用实现了这个接口的一些服务。那么为了使用以前实现旧接口的服务,我们就应该把新的接口转换成旧接口;实现这个转换的类就是抽象意义的转换器。相比于适配器的应用场景,代理就不一样了,虽然代理也同样是增加了一层,但是,代理提供的接口和原本的接口是一样的,代理模式的作用是不把实现直接暴露给客户端,而是通过代理这个层,代理能够做一些处理。

代理模式与委托的区别?

  1)代理是模式提供一种"一个类对另外一个类的控制权"是类与类之间关系;委托提供了"一种方法的执行会同时执行加载在上面的方法"是方法与方法之间的关系。

  2)委托可以代替代理,但是代理不能代替委托。

  3)委托可以动态加载方法,代理不能实现。

  4)委托对象所加载的方法不一定要属于同一个类。但是代理的类必须属于同一个类。   

参考: 

  https://www.cnblogs.com/zhili/p/proxypattern.html 

  https://www.cnblogs.com/chenwolong/p/proxy.html