type
status
date
slug
summary
tags
category
icon
password
comment_flag
SLUGS
实现
基于前文Composite模式,实现简单Demo
关注的问题
- 保持从子部件到父部件的引用能简化组合结构的遍历和管理。父部件引用可以简化结构的上移和组件的删除。通常在Component类中定义父部件引用。Leaf和Composite类可以继承这个引用以及管理这个引用的那些操作。
- Composte模式的目的之一是使得用户不知道他们正在使用的具体的Leaf和Composite类。因此,Component类应为Leaf和Composite类尽可能多定义一些公共操作。Component类通常为这些操作提供缺省的实现,而Leaf和Composite子类可以对它们进行重定义。
- 声明管理子部件的操作。虽然C omposite类实现了Add和Remove操作用于管理子部件,但在Composite模式中一个重要的问题是:在 Composite类层次结构中哪一些类声明这些操作。是应该在Component中声明这些操作,并使这些操作对 Leaf类有意义呢,还是只应该在Composite和它的子类中声明并定义这些操作呢?
- 存贮组件最好用哪一种数据结构? Composite可使用多种数据结构存贮它们的子节点,包括连接列表、树、数组和hash表。数据结构的选择取决于效率。
- 透明组合模式 和 安全组合模式 都有各自的优点和缺点,应该优先选择哪一种呢?透明组合模式 将公共接口封装到抽象根节点(Component)中,那么系统所有节点就具备一致行为,所以如果当系统绝大多数层次具备相同的公共行为时,采用 透明组合模式 也许会更好(代价:为剩下少数层次节点引入不需要的方法);而如果当系统各个层次差异性行为较多或者树节点层次相对稳定(健壮)时,采用安全组合模式
实例
场景
针对上一文中的iterator模式的餐馆合并实例,我们提出新的需求:
给正餐菜单增加“甜点”子菜单。如图,让甜点菜单变成正餐菜单中的一个子节点,我们想要的类似下图。但很明显,iterator模式的设计无法满足:
我们需要某种树状结构来容纳嵌套菜单和菜单项,因此我们需要改用Composite模式来进行设计。
代码
根据前面的模式结构,并结合上图:
首先设计
MenuComponent
抽象构件类,里面定义组合菜单和菜单项的共有方法后设计
CompositeMenu
和MenuItem
来继承MenuComponent
抽象类,这里选用透明式组合方式,即,我们仅在树枝结构中实现管理子节点的相关方法。最后定义服务员类
Waitress
类,并在main
中调用执行运行结果
与Iterator的结合
在新需求下,我们改用了Composite模式,然而问题来了:
- iterator模式的好处就烟消云散了,因为在本例中,Composite模式下对菜单的存储是通过
ArrayList
这一数据结构进行的。
- 并且,例子中使用的迭代都是递归调用的菜单项和菜单内部迭代的方式,属于内部迭代,如果我们需要外部迭代该怎么办?
首先我们来解决问题2:
加入有新需求:一位顾客只想看只含有蔬菜性质的菜单。如何实现?
step1: 由于
MenuComponent
抽象类中定义了所有对象的方法,我们现在该类中添加判断食品的方法,然后再在叶节点和树枝节点中进行重写step2-3: 在菜单项
MenuItem
中重写相关方法,注意,可能还需要定义新的变量和构造函数step4: 然后为了迭代组合中的每个对象,来调用
isVegetable()
,我们需要设计一个新的组合菜单迭代器CompositeIterator
。注意,这个迭代器中使用了递归的算法,可以递归的迭代树枝节点。step5-8: 接着在
MenuComponent
抽象类中添加创建迭代器的抽象方法,并在叶节点和树枝节点中进行重写。注意:叶节点没有子节点,所有创建的迭代器为空,所以需要定义一个空迭代器。空迭代器的定义
菜单项中重写
组合菜单中重写
这里的
GetMyItrFromArrayList
类是从ArrayList
中返回MyIterator
类型的迭代器,类似iterator模式一文中PancakeMenuIterator
的操作(本质上相同)step9: 在服务员类中添加新需求的业务处理函数
printVegetarianMenu()
然后再在
main
函数中进行测试结果
然后解决问题1:
注意到前面到例子中,创建组合菜单是通过新建
CompositeMenu
类,而在该类的内部是采用的ArrayList
这一数据结构,而在iterator模式一文的例子中,午餐餐馆的菜单是通过数组实现的,为了继续使用数组实现,我们将CompositeMenu
拷贝一份为CompositeMenu_ArrayVer
,并修改相关实现细节注意到
CompositeMenu_ArrayVer
中的createIterator
方法从数组对象中返回一个迭代器,因此参考iterator模式一文中的PancakeMenuIterator
,拷贝一份为GetMyItrFromArray
修改
CompositeIterator
对新的CompositeMenu_ArrayVer
聚合对象做适配对
Waitress
类的printVegetarinMenu()
方法适当修改然后在
main
函数中进行测试层次结构:
代码
结果
通过上面,就完成了composite模式与iterator模式的结合。
参考文章: