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