最近比较忙,有段时间没有更新设计模式的进度了。今天继续学习组合设计模式。

  组合模式的例子我们继续延续上篇《Head First设计模式——迭代器模式》的菜单例子,首先声明下迭代器和组合模式没有什么关系,他们是两个不同模式。只是我们在这个菜单例子的组合模式内部会用到迭代器。

迭代器模式中说到两个餐馆合并然后使用迭代器进行统一处理菜单的打印,但是现在有一个新的需求是原来大菜单中我们希望加入子菜单,比如饭后甜点。那么这个时候对于需求模型来说就是类似下面这样

菜单拥有菜单项,菜单项中可能还拥有子菜单,我们现在要打印菜单。也就是处理每个菜单和菜单项,如何将他们合理的组织起来并统一处理?要解决这个问题,组合模式来实现这一需求。

定义组合模式

组合模式:允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。

这个模式能够创建一个树形结构,如果我们有了一个树形结构的菜单、子菜单和可能还带有菜单项的子菜单,那么任何一个菜单都是一种“组合”。因为它既可以包含其他菜单,也可以包含菜单项。个别对象只是菜单项并未持有其他对象。

利用组合设计菜单

我们需要创建一个组件接口来作为菜单和菜单项的共同接口,让我们能够用统一的做法来处理菜单和菜单项,换句话说,我们可以针对菜单或菜单项调用相同的方法。

我们画出菜单设计的类图:

MenuComponent:提供接口,让菜单项和菜单共同使用。我们可能会对方法提供一些默认实现,所以我们可以使用抽象类。

MenuItem:继承自MenuComponent,覆盖了它有意义的方法(add,remove不用管)。

Menu:继承自MenuComponent,覆盖对它有意义的方法。

实现组合模式

实现菜单组件

  1. public abstract class MenuComponent
  2. {
  3. public virtual void Add(MenuComponent menuComponent) {
  4. throw new NotSupportedException();
  5. }
  6. public virtual void Remove(MenuComponent menuComponent)
  7. {
  8. throw new NotSupportedException();
  9. }
  10. public virtual MenuComponent GetChild(int i)
  11. {
  12. throw new NotSupportedException();
  13. }
  14. public virtual void GetName()
  15. {
  16. throw new NotSupportedException();
  17. }
  18. public virtual string GetDescription()
  19. {
  20. throw new NotSupportedException();
  21. }
  22. public virtual double GetPrice()
  23. {
  24. throw new NotSupportedException();
  25. }
  26. public virtual bool IsVegetarian()
  27. {
  28. throw new NotSupportedException();
  29. }
  30. public virtual void Print()
  31. {
  32. throw new NotSupportedException();
  33. }
  34. }

  实现菜单项

  1. public class MenuItme : MenuComponent
  2. {
  3. string name;
  4. string decription;
  5. bool vegetarian;
  6. double price;
  7.  
  8. public MenuItme(string name, string decription, bool vegetarian, double price)
  9. {
  10. this.name = name;
  11. this.decription = decription;
  12. this.vegetarian = vegetarian;
  13. this.price = price;
  14. }
  15.  
  16. public override string GetName()
  17. {
  18. return name;
  19. }
  20. public override string GetDescription()
  21. {
  22. return decription;
  23. }
  24. public override double GetPrice()
  25. {
  26. return price;
  27. }
  28. public override bool IsVegetarian()
  29. {
  30. return vegetarian;
  31. }
  32. public override void Print()
  33. {
  34. Console.Write(" " + GetName());
  35. if (IsVegetarian())
  36. {
  37. Console.Write("V" + GetName());
  38. }
  39. Console.WriteLine("," + GetPrice());
  40. Console.WriteLine(" --" + GetPrice());
  41. }
  42. }

  实现组合菜单

  1. public class Menu:MenuComponent
  2. {
  3. List<MenuComponent> menuComponents = new List<MenuComponent>();
  4. string name;
  5. string description;
  6. public Menu(string name, string description)
  7. {
  8. this.name = name;
  9. this.description = description;
  10. }
  11. public override void Add(MenuComponent menuComponent)
  12. {
  13. menuComponents.Add(menuComponent);
  14. }
  15. public override void Remove(MenuComponent menuComponent)
  16. {
  17. menuComponents.Remove(menuComponent);
  18. }
  19. public override MenuComponent GetChild(int i)
  20. {
  21. return menuComponents[i];
  22. }
  23. public override string GetName()
  24. {
  25. return name;
  26. }
  27. public override string GetDescription()
  28. {
  29. return description;
  30. }
  31.  
  32. public override void Print()
  33. {
  34. Console.Write("\n" + GetName());
  35. Console.WriteLine("," + GetDescription());
  36. Console.WriteLine("---------------------");
  37. foreach (var item in menuComponents)
  38. {
  39. item.Print();
  40. }
  41. }
  42. }

  这里菜单打印直接用foreach 循环打印菜单组件,如果遇到另外一个菜单对象则进入子菜单打印。此处就是使用迭代器模式,只不过我偷了个懒直接用了foreach,因为list C#已经实现了迭代器,使用foreach语法即可。《C# Foreach循环本质与枚举器》

测试

  1. MenuComponent breakfastMenu = new Menu("早餐菜单", "早餐供应");
  2. MenuComponent dinnerMenu = new Menu("晚餐菜单", "晚餐供应");
  3. MenuComponent dessertMenu = new Menu("甜点菜单", "晚餐甜点");
  4.  
  5. MenuComponent allMenus = new Menu("ALL MENUS", "all menus combaind");
  6. //加入菜单
  7. allMenus.Add(breakfastMenu);
  8. allMenus.Add(dinnerMenu);
  9. //加入菜单项
  10. breakfastMenu.Add(new MenuItme("包子", "鲜肉酱肉", false, 2));
  11. dinnerMenu.Add(new MenuItme("牛肉拉面", "拉面配牛肉", false, 15));
  12. dinnerMenu.Add(dessertMenu);
  13. dessertMenu.Add(new MenuItme("梦龙卷", "切件", false, 16));
  14.  
  15. allMenus.Print();

  

Head First设计模式——组合模式的更多相关文章

  1. 16. 星际争霸之php设计模式--组合模式

    题记==============================================================================本php设计模式专辑来源于博客(jymo ...

  2. Java设计模式——组合模式

    JAVA 设计模式 组合模式 用途 组合模式 (Component) 将对象组合成树形结构以表示“部分-整体”的层次结构.组合模式使得用户对单个对象和组合对象的使用具有唯一性. 组合模式是一种结构型模 ...

  3. 【设计模式】Java设计模式 - 组合模式

    Java设计模式 - 组合模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一起记录分享自己 ...

  4. c#设计模式-组合模式

    在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系统中目录的处理就是这样的一个例子,因为目录可以包括单独的文件,也可以包括文件夹,文件夹又是由文件组成的,由于简单对象和复合对象 ...

  5. [Head First设计模式]生活中学设计模式——组合模式

    系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...

  6. JAVA 设计模式 组合模式

    用途 组合模式 (Component) 将对象组合成树形结构以表示“部分-整体”的层次结构.组合模式使得用户对单个对象和组合对象的使用具有唯一性. 组合模式是一种结构型模式. 结构

  7. javascript设计模式-组合模式

    组合模式所要解决的问题: 可以使用简单的对象组合成复杂的对象,而这个复杂对象有可以组合成更大的对象.可以把简单这些对象定义成类,然后定义一些容器类来存储这些简单对象. 客户端代码必须区别对象简单对象和 ...

  8. 设计模式组合模式(Composite)精华

    23种子GOF设计模式一般分为三类:创建模式.结构模型.行为模式. 创建模式抽象的实例,他们帮助如何创建一个系统独立.这是一个这些对象和陈述的组合. 创建使用继承类的类架构更改实例.的对象类型模型的建 ...

  9. 设计模式 -- 组合模式 (Composite Pattern)

    定义: 对象组合成部分整体结构,单个对象和组合对象具有一致性. 看了下大概结构就是集团总公司和子公司那种层级结构. 角色介绍: Component :抽象根节点:其实相当去总公司,抽象子类共有的方法: ...

  10. javascript设计模式——组合模式

    前面的话 在程序设计中,有一些和“事物是由相似的子事物构成”类似的思想.组合模式就是用小的子对象来构建更大的对象,而这些小的子对象本身也许是由更小的“孙对象”构成的.本文将详细介绍组合模式 宏命令 宏 ...

随机推荐

  1. TensorFlow 中的卷积网络

    TensorFlow 中的卷积网络 是时候看一下 TensorFlow 中的卷积神经网络的例子了. 网络的结构跟经典的 CNNs 结构一样,是卷积层,最大池化层和全链接层的混合. 这里你看到的代码与你 ...

  2. iptables 网址转译 (Network Address Translation,NAT)

    当封包流经NAT電腦時,其位址/通訊端口會被修改,以達到改变包目的地(或旅程),或是让目的地误以为包是源自NAT电脑的效果.換言之,对封包执行NAT的电脑,可以成为新包的来源或目的地,或是成为真正来源 ...

  3. springmvc使用javabean作为请求参数

    1  首先写两个javabean对象  person 和 address 代码如下.两个类之间的关系如代码中 package cn.bean.demo.bo; public class Person ...

  4. 如何查看redis内存使用情况

    https://jingyan.baidu.com/article/2c8c281dbd079f0008252a0f.html Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以 ...

  5. javascript 变量的提升

    下面是一个关于全局和局部作用域的问题 var a = 123; function f(){ alert(a); var a = 1; alert(a); } f(); 大家第一眼看到后都会认为第一次a ...

  6. Adam那么棒,为什么还对SGD念念不忘 (2)—— Adam的两宗罪

    在上篇文章中,我们用一个框架来回顾了主流的深度学习优化算法.可以看到,一代又一代的研究者们为了我们能炼(xun)好(hao)金(mo)丹(xing)可谓是煞费苦心.从理论上看,一代更比一代完善,Ada ...

  7. 【u228】圣诞树

    [问题描述] 圣诞特别礼物挂在一棵圣诞树上,这棵树有n层,每层有一件礼物,每件礼物都有一个价值,有的礼物还有一些连结线,与下层的礼物相连,领取礼物的规则如下:任选一件礼物,它的下面如果有连结线,则可以 ...

  8. win10 uwp 解决 SerialDevice.FromIdAsync 返回空

    调用 SerialDevice.FromIdAsync 可能返回空,因为没有设置 package.appmanifest 可以使用端口 打开 package.appmanifest 文件添加下面代码 ...

  9. 51nod 范德蒙矩阵

    思路: 根据矩阵乘法的定义,G中的第i行第j列的元素 ai,j ,对答案的贡献为 ai,j∗ T中第j行的所有元素之和. 因此我们可以将T中根据每行的和进行排序.第i行的和可以通过公式 (ai^n−1 ...

  10. SpringBoot优先级

    1.配置文件 application.properties和application.yml文件可以放在以下四个位置: 外置,在相对于应用程序运行目录的/congfig子目录里. 外置,在应用程序运行的 ...