委托(Delegate)模式定义了对象之间的一对一的关系,被委托方可以作为委托方的事件接收者或者数据源(Data Source),当它作为事件接受者的时候,可以认为它是一种特殊的观察者(参考小话设计模式(十七)观察者模式)。

有人认为委托模式和代理模式是一个东西。(⊙o⊙)…好吧,可能是因为觉得Delegate的部分发音像代理而且可以将就着翻译成代理,但是实际上这是不同的两种模式(参考小话设计模式(十二)代理模式)。

委托模式在IOS和Cocos2d-x(实际上就是借鉴了IOS的做法)得到了广泛的应用,二者分别用protocol(协议)和虚函数/纯虚函数实现被委托方的接口。而在C#里面可以用interface或者delegate(虽然是同名,但实际上是观察者模式的应用,参考C#语法小知识(四)委托delegate)。

考虑这种情况,游戏中有一个商店,可以出售货物,而我们希望货物的数据源可以更换,那么就可以考虑使用委托模式。

数据源接口:

public interface IShopDataSource
{string GetItem (int idx);int ItemCount();
}

如果我们希望道具卖出时可以处理一些事件,那么可以定义委托接口:

public interface IShopDelegate
{void ItemSold (Shop shop, int idx);
}

商店定义:

public class Shop
{public Shop(IShopDataSource dataSource_, IShopDelegate shopDelegate_){dataSource = dataSource_;shopDelegate = shopDelegate_;}public IShopDataSource dataSource { get; set; }public IShopDelegate shopDelegate{ get; set;}public void ShowItemList(){if (dataSource == null) {return;}int count = dataSource.ItemCount ();for (int i = 0; i < count; i++) {Console.WriteLine (dataSource.GetItem(i));}}public void SellItem(int idx){if (shopDelegate == null) {return;}shopDelegate.ItemSold (this, idx);}
}

商店数据源定义:

public class ShopDataSource : IShopDataSource, IShopDelegate
{List<string> _items = new List<string>();public ShopDataSource(params string[] args){_items.AddRange (args);}public string GetItem (int idx){if (idx >= _items.Count) {return null;}return _items[idx];}public int ItemCount(){return _items.Count;}public void ItemSold(Shop shop, int idx){if (idx >= _items.Count) {return;}_items.RemoveAt (idx);shop.ShowItemList ();}
}

使用:

     ShopDataSource sds = new ShopDataSource("Apple", "Pen", "Pineapple");Shop shop = new Shop (sds, sds);shop.ShowItemList ();shop.SellItem (1);

可能会有人问,既然ShopDataSource继承了两个接口,那么为什么不把这两个接口合并呢?
当我们希望商店可以无限卖出道具的时候,那么ShopDataSource再继承自IShopDelegate就没有什么意义了。
当然,我们也可以声明一个ShopDelegate,它就负责显示第几个货物被卖出了:

public class ShopDelegate : IShopDelegate
{public void ItemSold(Shop shop, int idx){Console.WriteLine (idx);}
}

而且,我们可以设置shop的dataSource或者shopDelegate来修改数据源或事件接收者。

委托模式的好处,可以实现对象具体逻辑和被委托方(数据源和事件接收者)之间的松耦合,这一点在IOS的UITableView和cocos2d-x的TableView里得到了很好的体现。

坏处在于,如果接口方法太多,那么被委托方的实际类可能会需要实现很多无关的方法,尤其对于c#来讲。

不过使用c#的delegate可以很好的解决这个问题。

新的商店定义:

public class NewShop
{public delegate int DelegateItemNum();public delegate string DelegateGetItem(int idx);public delegate void DelegateItemSold(NewShop shop, int idx);public DelegateItemNum itemNumDelegate { protected get; set;}public DelegateGetItem getItemDelegate { protected get; set;}public DelegateItemSold itemSoldDelegate { protected get; set;}public void ShowItemList(){if (itemNumDelegate == null || getItemDelegate == null) {return;}int count = itemNumDelegate ();for (int i = 0; i < count; i++) {Console.WriteLine (getItemDelegate(i));}}public void SellItem(int idx){if (itemSoldDelegate == null) {return;}itemSoldDelegate (this, idx);}
}

为了保证一对一的关系,我们将三个delegate的属性设置为可写不可读(屏蔽了+=和-=操作),因为对于一个商店来讲添加多个数据源在大多数情况下并不合适,但实际上itemSoldDelegate这个方法并不需要这样做。

新的被委托方定义:

public class NewShopDelegate
{List<string> _items = new List<string>();public NewShopDelegate(NewShop newShop, params string[] args){newShop.itemNumDelegate = ItemCount;newShop.getItemDelegate = GetItem;newShop.itemSoldDelegate = (shop, idx) => {if (idx >= _items.Count) {return;}_items.RemoveAt (idx);shop.ShowItemList ();};_items.AddRange (args);}public string GetItem (int idx){if (idx >= _items.Count) {return null;}return _items[idx];}public int ItemCount(){return _items.Count;}
}

使用:

     NewShop newShop = new NewShop ();NewShopDelegate nsd = new NewShopDelegate(newShop, "Apple", "Pen", "Pineapple");newShop.itemSoldDelegate = (newShop_, idx) => {Console.WriteLine(idx);};newShop.ShowItemList ();newShop.SellItem (1);

小话设计模式(番外二)委托模式相关推荐

  1. 小话设计模式(十)外观模式

    外观(Fascade)模式定义一个高级的接口,将子系统里的一组接口整合起来,提供了一个统一的外观. 在以下情况下可以考虑使用外观模式: (1)设计初期阶段,应该有意识的将不同层分离,层与层之间建立外观 ...

  2. 小话设计模式三:发布/订阅模式

    发布/订阅模式定义: 又称为观察者模式,定义对象间的一种一对多的依赖关系,一个发布者可以对应多个订阅者,当发布者发生变化的时候,他可以将消息一一通知给所有的订阅者当一个对象的状态发生改变时,所有依赖于 ...

  3. 小话设计模式(九)组合模式

    组合(Composite)模式将对象组合成树形结构以表示"部分-整体"的层次结构.这样使得用户对单个对象和组合对象的使用具有一致性. 组合模式,听名字你可能比较陌生,但是你很可能是 ...

  4. C#软件设计——小话设计模式原则之:依赖倒置原则DIP

    前言:很久之前就想动笔总结下关于软件设计的一些原则,或者说是设计模式的一些原则,奈何被各种bootstrap组件所吸引,一直抽不开身.群里面有朋友问博主是否改行做前端了,呵呵,其实博主是想做" ...

  5. C#软件设计——小话设计模式原则之:接口隔离原则ISP

    前言:有朋友问我,设计模式原则这些东西在园子里都讨论烂了,一搜一大把的资料,还花这么大力气去整这个干嘛.博主不得不承认,园子里确实很多这方面的文章,并且不乏出色的博文.博主的想法是,既然要完善知识体系 ...

  6. C#设计模式之十二代理模式(Proxy Pattern)【结构型】

    一.引言 今天我们要讲[结构型]设计模式的第七个模式,也是"结构型"设计模式中的最后一个模式,该模式是[代理模式],英文名称是:Proxy Pattern.还是老套路,先从名字上来 ...

  7. 【23种设计模式专题】二 工厂模式

    程序猿学社的GitHub,欢迎Star github技术专题 本文已记录到github 文章目录 前言 小故事 传统方式 简单工厂(第一种) 工厂方法模式(第二种) 抽象工厂模式(第三种) 使用工厂方 ...

  8. 小话设计模式(二)工厂方法模式

    工厂方法(Factory Method)由名虚构造器(Virtual Constructor),是一种创建型的设计模式.使用工厂模式的意图便是定义一个用于创建对象的接口,让子类决定实例化哪一个类.它使 ...

  9. 小话设计模式五:模板方法模式

    模板方法模式定义: 定义一个操作中的算法骨架,而将一些实现步骤延迟到子类当中.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤. 模板方法解析: 模板方法模式是比较简单的一种设计 ...

最新文章

  1. 区块链相关论文研读2 - vChain,关于可验证的查询
  2. discuz“附件文件无法保存到远程服务器”故障的解决
  3. 奇奇怪怪的大佬:理发店小弟到阿里P10
  4. Github高级搜索技巧
  5. Linux编译动态链接库
  6. Python语言学习:python语言代码调试—异常处理之详细攻略
  7. Android Service演义
  8. pycharm中一直跳出updating indices...indexing
  9. SpringBoot集成JPA根据实体类自动生成表
  10. 第十讲:Obj-C Blocks 应用
  11. win10雷电3接口驱动_技嘉推出B550 主板首发雷电3接口:40Gbps速率、Intel主控
  12. EntityFramework之迁移操作(五)
  13. ThinkPHP5.0之控制器中常用操作
  14. Q:判断链表中是否存在环的相关问题
  15. 2021年5月软考网络工程师上午真题(带答案解析)上
  16. 钉钉自动打卡-智能填表
  17. 白话区块链 之1: 为什么账本要这么记?
  18. python打开txt文件
  19. 官方通知:考研国家线预计4月中旬公布
  20. 文本生成图像Text-To-Image评估指标IS、FID、VSS、R-precision

热门文章

  1. python编程基础与数据分析_Python编程基础与数据分析
  2. [统计模型] 基于R的潜在剖面分析(LPA)
  3. Java技巧之双括弧初始化
  4. 打印乘法口诀表(两种方法)
  5. vs2013 番茄助手Visual AssistX插件的安装与使用
  6. python股票全套系统_用python来炒股三 炒股交易系统(法则)
  7. 人生就是一场直播——经蓓老师莅临大米时代公益讲座
  8. C++性能优化(十一) —— 内存管理器性能分析
  9. 带附件的邮件的发送方法
  10. endnote中CWYW无文件_文献管理工具(三):EndNote 操作指南(免费在线版)