07.为别人做嫁衣 - 代理模式(Proxy)

7.1别为人做嫁衣!

  • 时间: 3月17日19点    地点: 小菜大鸟所住的客厅    人物: 大鸟, 小菜

     “小菜, 今天加这个叫娇娇的美女如何啊?” 大鸟一回家来就问小菜.
     “嗨, 别提了, 人家是有男朋友的.” 小菜无精打采的回答道.

     “有男朋友了啊, 这倒是我没料到, 那为什么还找你帮忙修电脑?”
     “她男朋友叫戴励, 在北京读大学呢, 他们高中就开始谈恋爱了.” 小蔡说, “而且他还告诉我了一件比较有趣的事.”
     “哦, 是什么?”
     “是这样的, 我们在吃饭的时候, 我就问他, 怎么不找男朋友帮忙修电脑. 他说男朋友在北京读书, 所以没办法帮助修. 我心里一想, ‘你在上海怎么男朋友会在北京’, 正想问他们是怎么认识的, 他却接着问我想不想知道她男朋友追他的事. 哈, 这不正是我所希望的吗, 于是我就跟着他开始了美好的回忆.”
     “又不是你谈恋爱, 说得这么肉麻, 还 ‘美好的回忆’. 她回忆什么了.”
     “当时他是这么说的: ‘那时我在高中二年级时的一个下午…….’”

  • 时间: 五年前的一天下午放学时   地点: 缴交所在中学高中二年级教室   人物: 娇娇, 戴励, 卓贾易

     “娇娇同学, 这是有人送你的礼物.” 一个男生手拿着一个芭比娃娃送到他的面前.
     “戴励同学, 这是什么意思?” 娇娇望着同班的这个男生, 感觉很奇怪.
     “是这样的, 我的好朋友, 隔壁三班的卓贾易同学, 请我带他送你这个礼物的.” 戴励有些脸红.
     “为什么要送我礼物, 我不认识他呀.”
     “他说……他说…..他说想和你交个朋友.” 戴励脸更红了, 有手抓后脑勺, 说话吞吞吐吐.
     “不用这样, 我不需要礼物的.” 娇娇显然想拒绝.
     “别别别, 他是我最好的朋友, 他请我代他送礼物给你, 也是下了很大决心的, 你看在我之前时常帮你辅导数学提的面子上, 就接收一下吧.” 戴励有些着急.
     “那好吧, 今天我对解析几何的椭圆那里还是不太懂, 你再给我讲讲.” 娇娇提出条件后结果礼物.
     “没问题, 我们到教室去讲吧.” 戴励松了口气.
     …….
     几天后
     “娇娇, 这是卓贾易送你的花.”
     “娇娇, 这是卓贾易送你的巧克力.”
     “我不要她送的东西了, 我也不想和他交朋友. 我愿意….我愿意和你做朋友!” 娇娇终于忍不住了. 直接表白.
     “啊!…..我不是在做梦吧…..” 戴励喜从天降, 不敢相信.
     “呆子!” 娇娇微笑地骂道.
     戴励用手抓了抓头发说, “其实我也喜欢你. 不过….不过, 那我该如何向卓贾易交代呢?”
     ……
     从此戴励何娇娇开始恋爱了. 毕业后, 戴励考上了北京xx大学, 而娇娇读了上海的大专.

  • 时间: 3月17日19点30分   地点: 小菜大鸟住所的客厅   人物: 大鸟 小菜

     “喂, 醒醒, 还在陶醉呀. 这个戴励根本就是一个大骗子, 那有什么卓贾易, 这是他自己想泡妞找的借口.” 大鸟不屑一顾.
     “我当时也是这么想的, 但他说真的是有这么个人, 后来那个卓贾易气死了, 差点和代理翻脸.” 小擦肯定的说.
     “那就不要怪戴励了, 卓贾易这个人就是在为被人做嫁衣, 所以自己苦恼也是活该, 谁家他不自己主动, 找人代理谈恋爱, 神经病啊.”
     “是呀, 都怪他自己, 为别人做嫁衣的滋味不好受啊.”
     “这里又可以谈到一个设计模式了.”
     “代理模式吧.”
     “小菜真的是越来越聪明了.”
     “去去去, 口是心非的东西, 代理模式又是怎么讲的?”
     “你先试着写如果卓贾易直接去追娇娇, 应该如何做?”

7.2 没有代理的代码

     十分钟后, 小菜写出了第一份代码



追求者类.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Pursuit {
SchoolGirl mm;
public Pursuit(SchoolGirl mm) {
this.mm = mm;
}
public void giveDolls() {
System.out.println(mm.getName() + "送你洋娃娃");
}
public void giveFlowers() {
System.out.println(mm.getName() + "送你鲜花");
}
public void giveChocolate() {
System.out.println(mm.getName() + "送你巧克力");
}
}

被追求者类

1
2
3
4
5
6
7
8
9
10
11
public class SchoolGirl {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

客户端代用代码如下

1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args){
SchoolGirl jiaojiao = new SchoolGirl();
jiaojiao.setName("李娇娇");
// 娇娇不是卓贾易, 此处有问题
Pursuit zhuojiayi = new Pursuit(jiaojiao);
zhuojiayi.giveDolls();
zhuojiayi.giveFlowers();
zhuojiayi.giveChocolate();
}

     “小菜, 娇娇并不认识卓贾易, 这样写不久等有他们之间相互认识, 并且是卓贾易亲自送东西给娇娇了吗?”
     “是呀, 这如何处理?”
     “嗯哼, 你忘了戴励了?”
     “哈, 对的对的, 戴励就是代理呀”

7.3 只有代理的代码

     十分钟后



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Proxy {
SchoolGirl mm;
public Proxy(SchoolGirl mm) {
this.mm = mm;
}
public void giveDolls() {
System.out.println(mm.getName() + "送你洋娃娃");
}
public void giveFlowers() {
System.out.println(mm.getName() + "送你鲜花");
}
public void giveChocolate() {
System.out.println(mm.getName() + "送你巧克力");
}
}

客户端代码

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args){
SchoolGirl jiaojiao = new SchoolGirl();
jiaojiao.setName("李娇娇");
Proxy daili = new Proxy(jiaojiao);
daili.giveDolls();
daili.giveFlowers();
daili.giveChocolate();
}

     “小菜, 你又犯错了.”
     “这又有什么问题, 为什么出错的总是我.” 小菜非常的不爽.
     “你把 Pursuit 换成了 Proxy , 把 ‘卓贾易’ 换成了 ‘戴励’ . 这就使得这个礼物变成了戴励送的, 而你刚才还肯定地说, ‘卓贾易’ 这个认识存在的, 礼物是他买的, 你这怎么能正确呢?”
     “哦, 我明白了, 我这样写吧Pursuit 给忽略了, 事实上应该是Pursuit通过 Proxy 送给 SchoolGirl 礼物, 这才是合理的. 那我应该如何办呢? “
     “不难啊, 你仔细观察一下, PuisuitProxy 有没有相似的地方?”
     “他们应该都有送礼物的是哪个方法, 只不过 Proxy 送的礼物是Pursuit买的, 实质是 Pursuit 送的.”
     “很好, 既然两者都有相同的方法, 那就意味着他们都怎么样?”
     “哦, 你的意思是他们都实现了相同的接口? 我想, 我可以写出代码来了.”
     “小菜开窍了.”

7.4 符合实际的代码

     十分钟后. 小菜的第三份代码.



代理接口如下

1
2
3
4
5
6
7
public interface IGiveGift {
void giveDolls();
void giveFlowers();
void giveChocolate();
}

追求者类如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Pursuit implements IGiveGift{ // 让'追求者'实现'送礼物'接口
SchoolGirl mm;
public Pursuit(SchoolGirl mm) {
this.mm = mm;
}
public void giveDolls() {
System.out.println(mm.getName() + "送你洋娃娃");
}
public void giveFlowers() {
System.out.println(mm.getName() + "送你鲜花");
}
public void giveChocolate() {
System.out.println(mm.getName() + "送你巧克力");
}
}

代理如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Proxy implements IGiveGift{ // '代理'也去试下送礼物接口
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();
}
}

客户端如下

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args){
SchoolGirl jiaojiao = new SchoolGirl();
jiaojiao.setName("李娇娇");
Proxy daili = new Proxy(jiaojiao);
daili.giveDolls();
daili.giveFlowers();
daili.giveChocolate();
}

     “这下好了, 娇娇不认识追去他的人, 但是可以通过代理人得到礼物. 效果其实是达到了.”
     “这就是代理模式. 好了, 我们来看看 GoF 对代理模式是如何描述的.”

7.5 代理模式 (Proxy Pattern)

代理模式(Proxy Pattern), 为其他对象提供一种代理以控制对这个对象的访问.[DP]



Subject 类, 定义了一个了 RealSubjectProxy 的公共接口, 这样就在任何使用 RealSubject 的地方都可以使用 Proxy

1
2
3
public abstract class Subject {
public abstract void request();
}

RealSubject 类, 定义 Proxy 所代表的真实实体

1
2
3
4
5
6
public class RealSubject extends Subject {
@Override
public void request() {
System.out.println("真实的请求");
}
}

Proxy 类, 保存一个引用是的代理可以访问实体, 并提供一个与 Subject 接口相同的接口, 这个代理就可以用来代替实体.

1
2
3
4
5
6
7
8
9
10
11
12
public class Proxy extends Subject {
RealSubject realSubject;
@Override
public void request() {
if (null != realSubject) {
realSubject = new RealSubject();
}
realSubject.request();
}
}

客户端代码

1
2
3
4
public static void main(String[] args){
Proxy proxy = new Proxy();
proxy.request();
}

7.6 代理模式应用

     “那代理模式都用在一些什么场合呢?” 小菜问道.
     “一般来说分为几种, 第一, 远程代理, 也就是为一个对象在不同的资质控件提供局部代表. 这样可以影藏一个对象存在与不同的地址空间的事实.[DP].”
     “有没有什么例子?”
     “哈, 其实你是一定用过的, WebService 在 .NET 中的应用是怎么做的?”
     “哦, 我明白什么叫做远程代理了, 当我在应用程序的项目中加入一个 Web 引用, 应用一个 WebService, 此是会在项目中生成一个 WebReference 的文件夹和一些文件, 其实他们就是代理, 这就使得客户端程序调用代理就可以解决远程访问的问题. 原来这就是代理模式的应用呀.”
     “第二种应用是虚拟代理, 是更具需要创建开销很大的对象. 通过他来存存放实例化需要很长时间的真是对象[DP]. 这样就可以达到性能的最优化, 比如说, 你打开一个很大的 HTML 网页时, 里面可能有很多的文字和图片, 但是你还是可以很快的打开它, 此是你所看到的是所有的文字, 但是图片确实一张一张的下载才看到的. 那些未打开的图片框, 就是通过虚拟代理来代替的真是的图片, 此是代理取出了真实图片的路径和尺寸.”
     “哦, 原来浏览器当中使用代理模式来优化下载的.”
     “第三种是安全代理, 用来控制真是对象访问时的权限[DP],. 一般用于对象应该有不同的访问权限的时候. 第四种是智能指引, 是指调用真实的对象时, 代理处理另外一些事[DP]. 如计算真实对象的引用次数, 这样当该对象没有引用时, 就自动释放他; 或当地一次引用一个持久对象时, 将他装入内存; 或在访问一个实际对象前, 检查是否已经锁定他, 以确保其他对象不能改变它. 他们都是通过代理在访问一个对象时附加一些内务处理.”
     “啊, 原来代理可以做这么多的事情, 我还以为他是一个很不常用的模式呢.”
     “代理模式其实就是访问对象时引入一定程度的间接性, 因为这种间接性, 可以附加多种用途.”
     “哦, 明白. 说白了, 代理就是真是对象的代表.”

7.7 秀才让小刘代其求婚

    ”好了, 看会电视吧, 好几天没有看 武林外传 了.” 大鸟打开电视, 此是武林外传正在播放第22集.
     “吕秀才, 是你让小刘想我求婚的吧?”
     “造物弄人!” 吕秀才惨惨的回答道, “这只是一个玩笑.”
     “哦!….玩笑!” 郭芙蓉冷冷的说, “我杀了你!”

~感谢捧场,您的支持将鼓励我继续创作~