为别人做嫁衣—代理模式

继上一篇“穿什么有这么重要?——装饰模式”后,本文继续讲解《大话设计模式》第七章“为别人做嫁衣—代理模式”。喜欢本书请到各大商城购买原书,支持正版。

为别人做嫁衣

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

“小菜,今天见这个叫娇娇的美女见得如何呀?”大鸟一回家来就问小菜。

“嗨,别提了,人家是有男朋友的。”小菜无精打采地答道。

“有男朋友了啊,这倒是我没料到,那为什么还找你帮忙修电脑?”

“她男友叫戴励,在北京读大学呢,他们高中就开始谈恋爱了。”小菜说,“而且她还告诉了我一件比较有趣的事。”

“哦,是什么?”

“是这样的,我们在吃饭的时候,我就问她,怎么不找男友帮修电脑。她说男友在北京读书,所以没办法帮助修。我心里一想,‘你在上海怎么男友会在北京’,正想问他们是怎么认识的,她却接着问我想不想知道他男友追她的事。哈,这不正是我所希望的吗,于是我就跟着她开始了美好的回忆。”

“又不是你谈恋爱,说得这么肉麻,还‘美好的回忆’。她回忆什么了?”

“当时她是这么说的:‘那是在我高中二年级时的一天下午……’”

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

“娇娇同学,这是有人送你的礼物。”一个男生手拿着一个芭比娃娃送到她的面前。

“戴励同学,这是什么意思?”娇娇望着同班的这个男生,感觉很奇怪。

“是这样的,我的好朋友,隔壁三班的卓贾易同学,请我代他送你这个礼物的。”戴励有些脸红。

“为什么要送我礼物,我不认识他呀。”

“他说……他说……他说想和你交个朋友。”戴励脸更红了,右手抓后脑勺,说话吞吞吐吐。

“不用这样,我不需要礼物的。”娇娇显然想拒绝。

“别别别,他是我最好的朋友,他请我代他送礼物给你,也是下了很大决心的,你看在我之前时常帮你辅导数学习题的面子上,就接受一下吧。”戴励有些着急。

“那好吧,今天我对解析几何的椭圆那里还是不太懂,你再给我讲讲。”娇娇提出条件后接过礼物。

“没问题,我们到教室去讲吧。”戴励松了口气。

……

几天后

“娇娇,这是卓贾易送你的花。”

……

“娇娇,这是卓贾易送你的巧克力。”

“我不要他送的东西了,我也不想和他交朋友。我愿意……我愿意和你做朋友!”娇娇终于忍不住了,直接表白。

“啊!……我不是在做梦吧……”戴励喜从天降,不敢相信。

“呆子!”娇娇微笑地骂道。

戴励用手抓了抓头发说,“其实我也喜欢你。不过……不过,那我该如何向卓贾易交待呢?”

……

从此戴励和娇娇开始恋爱了。毕业后,戴励考上了北京XX大学,而娇娇读了上海的大专。

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

“喂,醒醒,还在陶醉呀。这个戴励根本就是一个大骗子,哪有什么卓贾易,这是他自己想泡MM找的借口。”大鸟不屑一顾。

“我当时也是这么想的,但她说是真的有这个人,后来那个卓贾易气死了,差点和戴励翻脸。”小菜肯定地说。

“那就不能怪戴励了,卓贾易就是为别人在做嫁衣,所以自己苦恼也是活该,谁叫他不自己主动,找人代理谈恋爱,神经病呀。”

“是呀,都怪他自己,为别人做嫁衣的滋味不好受哦。”

“这里又可以谈到一个设计模式了。”

“你不说我也知道是哪一个,代理模式对吧?”

“哈,说得没错。小菜真是越来越聪明。”

“去去去,口是心非的东西,代理模式又是怎么讲的?”

“你先试着写如果卓贾易直接追娇娇,应该如何做?”

2 没有代理的代码

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

结构图
结构图

追求者

/// <summary>
/// 追求者
/// </summary>
class Pursuit
{
  SchoolGirl mm;
  public Pursuit(SchoolGirl mm)
  {
    this.mm = mm;

  }

  public void GiveDolls()
  {
    Console.WriteLine(mm.Name + "送你洋娃娃");
  }

  public void GiveFlowers()
  {
    Console.WriteLine(mm.Name + "送你鲜花");
  }

  public void GiveChocolate()
  {
    Console.WriteLine(mm.Name + "送你巧克力");
  }
}

被追求者类

/// <summary>
/// 被追求者
/// </summary>
class SchoolGirl
{
  private string name;
  public string Name
  {
    get { return name; }
    set { name = value; }
  }
}

客户端调用代码如下:

static void Main(string[] args)
{
  SchoolGirl jiaojiao = new SchoolGirl();
  jiaojiao.Name = "李娇娇";

  // 娇娇并不认识卓贾易,此处有问题
  Pursuit zhuojiayi = new Pursuit(jiaojiao);

  zhuojiayi.GiveDolls();
  zhuojiayi.GiveFlowers();
  zhuojiayi.GiveChocolate();

  Console.Read();
}

“小菜,娇娇并不认识卓贾易,这样写不就等于他们之间互相认识,并且是卓贾易亲自送东西给娇娇了吗?”

“是呀,这如何处理?”

“咦,你忘了戴励了?”

“哈,对的对的,戴励就是代理呀。”

3 只有代理的代码

十分钟后

结构图
结构图
class Proxy
{
  SchoolGirl mm;
  public Proxy(SchoolGirl mm)
  {
    this.mm = mm;

  }

  public void GiveDolls()
  {
    Console.WriteLine(mm.Name + "送你洋娃娃");
  }

  public void GiveFlowers()
  {
    Console.WriteLine(mm.Name + "送你鲜花");
  }

  public void GiveChocolate()
  {
    Console.WriteLine(mm.Name + "送你巧克力");
  }
}

客户端代码

static void Main(string[] args)
{
  SchoolGirl jiaojiao = new SchoolGirl();
  jiaojiao.Name = "李娇娇";

  // 此时,“追求者”类的实例“桌贾易”又不在了
  Proxy daili = new Proxy(jiaojiao);

  daili.GiveDolls();
  daili.GiveFlowers();
  daili.GiveChocolate();

  Console.Read();
}

“小菜,你又犯错了。”

“这又有什么问题,为什么出错的总是我。”小菜非常不爽。

“你把‘Pursuit(追求者)’换成了‘Proxy(代理)’,把‘卓贾易’换成了‘戴励’。这就使得这个礼物变成是戴励送的,而你刚才还肯定地说,‘卓贾易’这个人是存在的,礼物是他买的,你这怎么能正确呢?”

“哦,我明白了,我这样写把‘Pursuit(追求者)’给忽略了,事实上应该是‘Pursuit(追求者)’通过‘Proxy(代理)’送给‘SchoolGirl(被追求者)’礼物,这才是合理的。那我应该如何办呢?”

“不难呀,你仔细观察一下,‘Pursuit(追求者)’和‘SchoolGirl(被追求者)’有没有相似的地方?”“他们应该都有送礼物的三个方法,只不过‘SchoolGirl(被追求者)’送的礼物是‘Pursuit(追求者)’买的,实质是‘Pursuit(追求者)’送的。”

“很好,既然两者都有相同的方法,那就意味着他们都怎么样?”

“哦,你的意思是他们都实现了同样的接口?我想,我可以写出代码来了。”“小菜开窍了。”

4 符合实际的代码

十分钟后。小菜第三份代码。

结构图
结构图

代理接口如下:

interface GiveGift
{
  void GiveDolls();
  void GiveFlowers();
  void GiveChocolate();
}

追求者类如下,唯一变化就是让“追求者”去实现“送礼物”接口

/// <summary>
/// 追求者
/// </summary>
class Pursuit : GiveGift
{
  SchoolGirl mm;
  public Pursuit(SchoolGirl mm)
  {
    this.mm = mm;

  }

  public void GiveDolls()
  {
    Console.WriteLine(mm.Name + "送你洋娃娃");
  }

  public void GiveFlowers()
  {
    Console.WriteLine(mm.Name + "送你鲜花");
  }

  public void GiveChocolate()
  {
    Console.WriteLine(mm.Name + "送你巧克力");
  }
}

代理类如下

/// <summary>
/// 让“代理”也去实现“送礼物接口
/// </summary>
class Proxy:GiveGift
{
  Pursuit gg;
  public Proxy(SchoolGirl mm)
  {
    gg = new Pursuit(mm);

  }

  public void GiveDolls()
  {
    // 在实现方法中去调用“追求者”类的相关方法
    gg.GiveDolls();
  }

  public void GiveFlowers()
  {
    gg.GiveFlowers();
  }

  public void GiveChocolate()
  {
    gg.GiveChocolate();
  }
}

客户端如下

static void Main(string[] args)
{
  SchoolGirl jiaojiao = new SchoolGirl();
  jiaojiao.Name = "李娇娇";

  Proxy daili = new Proxy(jiaojiao);

  daili.GiveDolls();
  daili.GiveFlowers();
  daili.GiveChocolate();

  Console.Read();
}

“这下好了,娇娇不认识追求她的人,但却可以通过代理人得到礼物。效果其实是达到了。”

“这就是代理模式。好了,我们来看看GoF对代理模式是如何描述的。”

5 代理模式

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

代理模式(Proxy)结构图
代理模式(Proxy)结构图

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

abstract class Subject
{
  public abstract void Request();
}

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

class Realsubject : Subject
{
  public override void Request()
  {
    Console.WriteLine("真实的请求");
  }
}

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

class Proxy : Subject
{
  Realsubject realSubject;
  public override void Request()
  {
    if (realSubject == null)
    {
      realSubject = new Realsubject();
    }
    realSubject.Request();
  }
}

客户端代码

Proxy proxy = new Proxy();
proxy.Request();

Console.Read();

6 代理模式应用

“那代理模式都用在一些什么场合呢?”小菜问道。

“一般来说分为几种,第一,远程代理,也就是为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。”

“有没有什么例子?”

“哈,其实你是一定用过的,WebService在.NET 中的应用是怎么做的?”

“哦,我明白什么叫远程代理了,当我在应用程序的项目中加入一个Web引用,引用一个 WebService,此时会在项目中生成一个 WebReference的文件夹和一些文件,其实它们就是代理,这就使得客户端程序调用代理就可以解决远程访问的问题。原来这就是代理模式的应用呀。”

“第二种应用是虚拟代理,是根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。这样就可以达到性能的最优化,比如说你打开一个很大的HTML网页时,里面可能有很多的文字和图片,但你还是可以很快打开它,此时你所看到的是所有的文字,但图片却是一张一张地下载后才能看到。那些未打开的图片框,就是通过虚拟代理来替代了真实的图片,此时代理存储了真实图片的路径和尺寸。”

“哦,原来浏览器当中是用代理模式来优化下载的。”

“第三种应用是安全代理,用来控制真实对象访问时的权限。一般用于对象应该有不同的访问权限的时候。第四种是智能指引,是指当调用真实的对象时,代理处理另外一些事。如计算真实对象的引用次数,这样当该对象没有引用时,可以自动释放它;或当第一次引用一个持久对象时,将它装入内存;或在访问一个实际对象前,检查是否已经锁定它,以确保其他对象不能改变它。它们都是通过代理在访问一个对象时附加一些内务处理。”

“啊,原来代理可以做这么多的事情,我还以为它是一个很不常用的模式呢。”

“代理模式其实就是在访问对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。”

“哦,明白。说白了,代理就是真实对象的代表。”

7 秀才让小六代其求婚

“好了,看会儿电视吧,好几天没看《武林外传》了。”大鸟打开了电视,此时武林外传正在播放第22集(站长注:这书果然有年头了,《武林外传》是05年播放的吧)。

当播放到最后片段时,剧中,郭芙蓉对吕秀才恶狠狠地说:“吕秀才,是你让小六向我求婚的吧?”

“造物弄人!”吕秀才惨惨地答道,“这只是一个玩笑。”

“哦!……玩笑!”郭芙蓉冷笑地说,“我杀了你!”

秀才速奔出去,郭芙蓉口中叫着“你给我站住!”跟着跑了出去……

小菜和大鸟看到这里,转头相互看着对方,小菜说:“吕秀才让燕小六代其向郭芙蓉求婚,这不就是……”,两人异口同声的说:“代—理—模—式!”

下一篇我们接着读“第8章 雷锋依然在人间——工厂方法模式 ”,欢迎关注微信公众号【乐趣课堂】。

原文出处:微信公众号【乐趣课堂】

原文链接:

本文观点不代表Dotnet9立场,转载请联系原作者。

发表评论

登录后才能评论