《Head First Design Patterns》笔记十一:组合模式(Composite Pattern)

概述

   我们知道,一个数据集里的往往不只是简单的元数据,往往同样嵌套的有子数据集,子数据集同样会嵌套,这就是树形结构,从跟部到最末端的叶子,一层层往下走,那么这种数据结构我们同样需要做到遍历,怎么办呢.

   ok,循环递归啊,判断是否枝丫还是叶子,是叶子就show出来,枝丫就递归一下.   这个是ok,但递归其实很复杂的,不少人可能会反对这一说法,很简单吗,编程的兄弟都会,不错,是不难,但为什么说很复杂呢,想象下,这个复杂在哪里,首先,需要暴露数据集存储方式,其次,客户需要的只是1行代码就实现,而不是去做麻烦的递归来得到数据.

分析

   那有没有办法能像处理单一元数据一样处理,而不需要管它是枝丫还是叶子呢,这就要看组合模式了,我们来看uml图1

 

     如上,我们建立Component接口,让leaf和Composite一起继承该接口,对于leaf的Operation(),就是直接执行本身的Operation(),对于Composite来说,就是遍历其所属子组件,让子组件执行Operation动作,

   这样的做的话,对于客户来说,要遍历的话只需要执行跟组件Component.Operation()这一句就可.

   但这里有一个问题,Component不支持添加,删除子数据的话,要做到这个首先要去判断是否是composite,如果是就把类型转换为Composite,再执行添加删除,这显然不是很友好.透明性差,

   那么我们在Component加上Add,remove方法怎么样呢,我们来看UMl图2

  

   ok,Component直接支持增删动作了,问题解决,但新问题来了,leaf作为末端同样也支持增删了,这是非法操作,没办法,我们只好在增删方法throw Exception了,这就是透明性变好了,但安全性变差了.

  那有没有别的方法呢.我们可以添加一个新的collection类,用来存放子组件,当是leaf的时候,设为null,如下uml图3

 

  遍历的时候只需要Operation,当增删子组件的时候,判断Childs是否为空,如果为空则为leaf,不为空则可以增删.这解决了前面的问题,就是增加了一个新类和childCollection是否为空的判断,个人喜欢这种,不过具体取舍还是看具体环境.

实例

    例子还是餐厅菜单,早餐,正餐,新要求是正餐需要添加甜点子菜单.要做到子菜单,光靠Iterator是不够的,Composite就刚好派上用场.

我们画应用uml,如下

  

  MenuItem作为菜式,menuCollection为空,menu为菜单,包含子菜单组件(菜单或则菜式)

  剩下就是代码了

实现

  首先是MenuComponent,MenuItem,Menu和MenuCollection了,实现composite模式,MenuCollection用到Iterator模式(就是Enumerable)

 

呵呵,接下来就是Waitress的实现

简单吧,除了Print()命令,Waitress不再关心传递过来的MenuComponent的其他信息.

然后就是测试代码了,Program.CS,如下

 

运行,结果如下

  --AllMenu:
  --Breakfast:
Pancake's price is 1.5
Waffle's price is 2
Egg's price is 0.5
  --Dinner:
Hotdog's price is 1.05
Soup of the day's price is 1
Blt's price is 4
  --Dessert for dinner:
ApplePie's price is 2
OrangePie's price is 2.5

 

 

下一篇:《Head First Design Patterns》笔记十二:状态模式(State Pattern)

上一篇:  《Head First Design Patterns》笔记十:迭代器模式(Iterator Pattern)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值