先给出代理模式UML结构:
图例引用自OKevin的博客:https://www.cnblogs.com/yulinfeng/p/5861988.html
引用OKevin博客中所述:
《大话设计模式》中对代理模式应用场合的解释
第一,远程代理,也就是为一个对象在不同地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。
第二,虚拟代理,是根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。
第三,安全代理,用来控制真实对象访问时的权限。
第四,智能指引,是指当调用真实对象的对象时,代理处理另外一些事。(这里和动态代理类似)
第一感觉是:代理模式跟装饰模式也太像了,后来查了一些资料,发现两者最主要的区别是:代理模式能够控制被代理的实体,但装饰模式则不行:
由于两者代码极为相似,我只列出其中有差异的部分:
public class ConcreteDecoratorA extends Decorator { public void do (ConcreteComponent c){ //加了点内容,装饰了一哈 c.do(); } }
显然,装饰模式仅仅是增强了ConcreteComponent类的do方法的功能,并不能阻止do()的运行,仅仅做对do()功能的延申,并且方法名要一样
public class Proxy extends Decorator { public void do (ConcreteComponent c){ if(proxy.buzy){ proxy.offline; }else{ proxy.online; c.do(); } } }
而代理模式可以决定ConcreteComponent之后的行为,可以在代理方法前后增加各种逻辑;
我个人结论是:装饰模式和代理模式是一种思维方式,只是为了作用在不同应用场景才细化为两种.
装饰模式在Java中非常常用,譬如,一些基本容器类:ArrayList和HashMap,他们都不是线程安全的类,但类库给我们提供了包装器工厂方法(例如Collections.synchronizedList等类似的方法),这些工厂方法通过装饰模式将非线程安全的容器类封装在一个同步的包装器对象之中,而包装器能将接口中的每个方法都实现为同步的,并将调用请求转发到底层的容器对象上,只要包装器对象拥有对底层容器对象的唯一引用,即把底层容器对象封闭在包装器中,那么它就成为线程安全的了。
下面着重谈谈代理模式:
public class Proxy implements Subject { private Conductor conductor; //注入售票员对象 @Override public void book(Passenger p) { //注入乘客对象 if(conductor.validate(p)){ //售票员验证乘客的身份 conductor.book(); //成功验证,办理购票 p.goAboard(); //乘客登机 }else{ conductor.call(911); //身份验证失败,售票员报警 p.captured(); //乘客(嫌疑人)被捕! } } }
利用继承,让诸如医生类,律师类,教师类等继承于乘客类,模拟机票的办理业务,让乘客类下不用去写买机票的相关代码,而乘客类下又有更多的类,也不用关心买票的相关业务,全权交给Proxy(想象成机场的业务规则)去安排售票员帮忙买票即可.
这相当于代码的抽取,将乘客类及其子类下众多的买票代码集成到代理类里来了,维护起来就非常方便,这是代理模式的优势之一.