设计模式之代理模式
代理模式英文名叫Proxy Pattern
看下Proxy的含义
[ˈprɑ:ksi]
n.代表权;代理人,代替物;委托书;
主要表达的就是代表、代替、委托的意思。
我对这个模式的理解是这样的:
一个服务或者是一个功能,一个对象。由于某种自身或者外界的原因,不能直接暴露出来,而是需要另外一个对象做一下跳转(也不一定是完全的跳转)。并且在这个过程中,最终实现功能或者是解决问题的实体并没有发生改变。
光说概念的话会比较抽象,我们举几个生活中的例子:
1>房产中介
如果户主打算拍卖掉房子,因此需要每天发广告、发消息,然后接待买家看房,和买家讨价还价。
这样的模式,相对来说比较简单,(也是很多新手喜欢的直接)。但是户主需要和每一个买家都进行接触。增加一个新的买家,就需要重新试探。流失一个买家,又有实时跟踪。这导致作为卖家的户主所要处理的事情越来越腌肿,买家关注了太多自己只用一次或者根本用不到的技能。
因此就需要引入一个代理:房产中介。
卖家将房子的信息:钥匙、报价、区间、卖房时间等整体告诉中介后。中介将所有的信息进行处理后公布出来。买房人再从中介处获取到自己所需要的信息,然后再通过中介与卖家沟通。
这样卖家就不需要再关注任何买房动态。只需要按照事先自己考虑的结果与代理进行商议即可。
2>明星经纪人
无论是娱乐明星还是体育明星,都需要有一个经纪人,或者有一个工作室。(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )这个工作室负责包装明星,制造舆论新闻,代表明星与制片方或者俱乐部谈判。而这些都不是明星需要直接关注的事情。明星任何的商务活动(谈判、签约等),都是通过代理人与外界进行接触的。
3>办事处
对于跨国企业来说,涉及到的业务往往是全球化的,很多业务往来存在政治、地区、时差等限制。因此有时这些机构就设置一个办事处,用来作为这些企业在当地的一个委托人,来治谈业务等。
这样做很好的体现出了对内提高内聚、对外降低耦合:
户主、明星、跨国企业都可以最大限度的聚焦于自身业务对外;(内聚)
户主、明星、跨国企业都不再需要过多的感知外界业务,通过代理这一层进行封装过滤,将真正属于户主(过户)、明星(演出)、跨国企业(生产制造)的业务传递给被代理人来操作。而对于外界来说大部分情况下,外界调用者并不感知到代理的存在,所有的事情与直接和被代理人谈是一样的。(解耦)
模式的结构可以理解为下图的样子:
可以看出代理方和被代理方都实现了一个对外接口。
这个接口是被代理方所有展示的所有方法。
调用方持有该接口的实现:代理人。
然后请求代理,代理再透传给该接口的另外一个实现:被代理人。真正的操作由被代理人来实现。(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )
可以通过如下代码来深度理解代理模式:
调用方
1 public class Invoker 2 { 3 public static void main(String[] args) 4 { 5 ISuperStar ronaldo = new SuperStarProxy("ronaldo"); 6 ronaldo.negotiate(); 7 ronaldo.signContract(); 8 ISuperStar messi = new SuperStarProxy("messi"); 9 messi.negotiate(); 10 messi.signContract(); 11 } 12 }
代理类
1 public class SuperStarProxy implements ISuperStar 2 { 3 private ISuperStar superStar = new SuperStar(); 4 private String superStarName; 5 6 public SuperStarProxy(String superStarName) 7 { 8 this.superStarName = superStarName; 9 10 } 11 12 @Override 13 public void signContract() 14 { 15 superStar.signContract(); 16 } 17 18 @Override 19 public void negotiate() 20 { 21 superStar.negotiate(); 22 } 23 24 }
被代理类
1 public class SuperStar implements ISuperStar 2 { 3 @Override 4 public void signContract() 5 { 6 // to do sth 7 return; 8 } 9 10 @Override 11 public void negotiate() 12 { 13 // to do sth 14 return; 15 } 16 }
接口
1 public interface ISuperStar 2 { 3 /** 4 * 签约 5 */ 6 public void signContract(); 7 8 /** 9 * 谈判 10 */ 11 public void negotiate(); 12 }
代理模式的几个用途:
1、进行安全代理控制
被代理方和调用方有时存在于两个不同的安全域中,我们需要通过一个安全过滤鉴权的管道进行控制。这种情况下就可以使用代理来完成安全鉴权的功能。
举个例子:比如公司的外网访问,有时需要设置一个网络代理
2、虚拟代理进行延迟加载
有时初始化数据时,需要过多的初始化数据时,可以通过代理延缓这种加载,等到真正调用时,再初始化。举个例子:有时用流量看公众号文章时,如果是GIF,系统会暂时只加载一个静态的图片,当用户确定要看该GIF时,再点击图片,加载真正的GIF,静态的图片就相当于是一个虚拟代理。
3、远程工作代理
有时我们要调用网络另外一侧的一个接口,每一个开发者都需要自己实现一个该远程网络的交互,交互方式是千差万别的。这时我们就会使用一个远程的工作代理,这个代理就是一个接口的实现。我们可以先使用该代理进行开发,同时开发者也感知不到接口真正的工作状态。当我们调用这个远程的代理时,代理在内部就自动的与远程的接囗进行交互。而本地的业务逻辑并不能感知到。
举个例子:数据库包中的JDBC,该包由数据库厂商提供,我们的业务代码只和JDBC进行交互,并不会直接使用各种网络协议与数据库进行交互
4、管控
有时我们需要添加接口访问日志、接口耗时、频次等。就可以在原有实现的基础上,加一层代理。将这些逻辑推倒代理中实现,降低业务实现类的代码污染。
代理模式的缺点:
通过代理模式,我们可以看出,该模式在内聚封装的同时,将一部分的业务逻辑移植到了代理人处。虽然降低了调用方和实现方之间的耦合,但是加入了一层新的耦合,就是代理方和调用方之间的耦合。当有任何逻辑变更时,都需要修改代理方,因此代理模式在降低耦合的同时,会导致代理类变得越来越雕肿、业务越来越复杂。
5、(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )
扩展:
由于代理方也是接口的实现方,随着接口的变化,代理方都需要添加新的逻辑实现。而这种实现需要在系统运行前就已经搭配,并实现完成。因此这种模式也称为静态代理模式。我们在这个时候,需要支持一种动态的,最好可以一劳永逸的代理方式。这种方式可以支持简单的相同的逻辑处理,之后就直接进行透传即可。这种代理模式我们称之为动态代理。这个我会在后边的文章中介绍。
如果你觉得写的不错,欢迎转载和点赞。 转载时请保留作者署名jilodream/王若伊_恩赐解脱(博客链接:http://www.cnblogs.com/jilodream/