代理模式 问题引入 问题描述 隔壁班的卓贾易想追求娇娇,但是他自己不好意思,就委托和娇娇同班的戴励帮助他。卓贾易给娇娇先后买了芭比娃娃、花、巧克力,饼委托戴励送给娇娇,却没想给娇娇和戴励创造了相处的机会。娇娇和戴励通过接触互生情愫,最后在一起了。卓贾易自然是很生气,一番追求却为他人做了嫁衣。但细细想来,虽说一直是卓贾易给娇娇买的礼物,但娇娇自始至终都是从戴励手里拿到的礼物,她并未接触过送礼之人——卓贾易。 现在我们想用程序来描述这一个故事,关键之处在于准确描述卓贾易、戴励及娇娇三者之间的行动关系。如果我们只描述了追求者卓贾易,和被追求者娇娇,则与实际情况不符,因为娇娇并不认识卓贾易;而若我们只描述了代理戴励,和被追求者娇娇,亦与实际情况不符,因为礼物是卓贾易买的,戴励并没有礼物直接送给娇娇。
隔壁班的卓贾易想追求娇娇,但是他自己不好意思,就委托和娇娇同班的戴励帮助他。卓贾易给娇娇先后买了芭比娃娃、花、巧克力,饼委托戴励送给娇娇,却没想给娇娇和戴励创造了相处的机会。娇娇和戴励通过接触互生情愫,最后在一起了。卓贾易自然是很生气,一番追求却为他人做了嫁衣。但细细想来,虽说一直是卓贾易给娇娇买的礼物,但娇娇自始至终都是从戴励手里拿到的礼物,她并未接触过送礼之人——卓贾易。
现在我们想用程序来描述这一个故事,关键之处在于准确描述卓贾易、戴励及娇娇三者之间的行动关系。如果我们只描述了追求者卓贾易,和被追求者娇娇,则与实际情况不符,因为娇娇并不认识卓贾易;而若我们只描述了代理戴励,和被追求者娇娇,亦与实际情况不符,因为礼物是卓贾易买的,戴励并没有礼物直接送给娇娇。为了准确描述他们三人的关系,我们可以考虑使用代理模式。
代理模式(Proxy Pattern)是指实现一个类代表另一个类的功能,为其他对象提供一种代理以控制对这个对象的访问。
代理模式(Proxy Pattern)可以应用到这一问题中。
这一问题中有三个类型的角色,追求者(卓贾易),代理(戴励)和被追求者(娇娇)。他们三者间的关系满足,追求者(卓贾易)委托代理(戴励),通过代理(戴励)给被追求者(娇娇)送礼物,而被追求者(娇娇)只与代理(戴励)有接触。
若使用代理模式描述,即代理(戴励)代表了追求者(卓贾易)的追求(赠送礼物)的功能,被追求者(娇娇)仅与代理(戴励)接触便收到了礼物。这样就实现了他们三人关系的准确描述。
使用代理模式来解决这一问题。
IGiveGift,定义追求者和代理的共用接口:
GiveDolls();GiveFlowers();GiveChocolate()。Pursuit,定义需要代理的真正实体,继承于抽象类IGiveGift:
Proxy,保存追求者实体的一个引用,使得代理可以访问实体,继承于抽象类IGiveGift,实现对实体的替代:
Pursuit对象;Pursuit的具体送礼操作此处我们使用Java语言来实现这一方案,C#语言实现可见原书原版,本项目的所有语言实现可见本项目Github仓库,其中包括:C++,Java,python,读者可按需参阅。
首先定义一个被追求者类,是为了使故事可以完整描述,无需实现特别的功能。
public class SchoolGirl { private String name; public SchoolGirl() {} public SchoolGirl(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
定义送礼物的抽象类IGiveGift。
public interface GiveGift { public void giveDolls(); public void giveFlowers(); public void giveChocolate(); }
追求者类增加了实现送礼物的接口的改动。
public class Pursuit implements GiveGift{ SchoolGirl mm ; public Pursuit(SchoolGirl mm) { this.mm = mm; } public void giveDolls() { System.out.println(mm.getName() + " give you a doll"); } public void giveFlowers() { System.out.println(mm.getName() + " give you a Flower"); } public void giveChocolate() { System.out.println(mm.getName() + " give you a chocolate"); } }
代理类,是唯一即认识追求者,又认识被追求者的类。初始化时与追求者及被追求者建立关联,实现送礼物方法时调用追求者的同名方法。
public class Proxy implements GiveGift { Pursuit gg; public Proxy(SchoolGirl mm) { this.gg = new Pursuit(mm); } public void giveDolls() { gg.giveDolls(); } public void giveFlowers() { gg.giveFlowers(); } public void giveChocolate() { gg.giveChocolate(); } }
客户端如下。
public class ProxyClient { public static void main(String[] args) { SchoolGirl jiaojiao = new SchoolGirl(); jiaojiao.setName("JiaoJiao Li"); Proxy proxy = new Proxy(jiaojiao); proxy.giveDolls(); proxy.giveFlowers(); proxy.giveChocolate(); } }
运行结果如下。
JiaoJiao Li give you a doll JiaoJiao Li give you a Flower JiaoJiao Li give you a chocolate
代理模式由三个主要角色组成:
结构图如下:

代理模式的通用结构示意图如下

不方便直接访问对象时,为不宜直接访问的对象提供一个访问层。
使用代理模式的方式分为以下几种:
模式优点包括:
模式缺点包括: