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模式的设计无法满足:
 
notion image
我们需要某种树状结构来容纳嵌套菜单和菜单项,因此我们需要改用Composite模式来进行设计。
代码
notion image
根据前面的模式结构,并结合上图:
首先设计MenuComponent抽象构件类,里面定义组合菜单和菜单项的共有方法
后设计CompositeMenuMenuItem来继承MenuComponent抽象类,这里选用透明式组合方式,即,我们仅在树枝结构中实现管理子节点的相关方法。
最后定义服务员类Waitress类,并在main中调用执行
运行结果

与Iterator的结合

在新需求下,我们改用了Composite模式,然而问题来了:
  1. iterator模式的好处就烟消云散了,因为在本例中,Composite模式下对菜单的存储是通过ArrayList这一数据结构进行的。
  1. 并且,例子中使用的迭代都是递归调用的菜单项和菜单内部迭代的方式,属于内部迭代,如果我们需要外部迭代该怎么办?
首先我们来解决问题2:
加入有新需求:一位顾客只想看只含有蔬菜性质的菜单。如何实现?
 
notion image
step1: 由于MenuComponent抽象类中定义了所有对象的方法,我们现在该类中添加判断食品的方法,然后再在叶节点和树枝节点中进行重写
step2-3: 在菜单项MenuItem中重写相关方法,注意,可能还需要定义新的变量和构造函数
step4: 然后为了迭代组合中的每个对象,来调用isVegetable(),我们需要设计一个新的组合菜单迭代器CompositeIterator。注意,这个迭代器中使用了递归的算法,可以递归的迭代树枝节点。
step5-8: 接着在MenuComponent抽象类中添加创建迭代器的抽象方法,并在叶节点和树枝节点中进行重写。注意:叶节点没有子节点,所有创建的迭代器为空,所以需要定义一个空迭代器。
空迭代器的定义
菜单项中重写
组合菜单中重写
这里的GetMyItrFromArrayList类是从ArrayList中返回MyIterator类型的迭代器,类似iterator模式一文中PancakeMenuIterator的操作(本质上相同)
step9: 在服务员类中添加新需求的业务处理函数printVegetarianMenu()
然后再在main函数中进行测试
结果
然后解决问题1:
notion image
注意到前面到例子中,创建组合菜单是通过新建CompositeMenu类,而在该类的内部是采用的ArrayList这一数据结构,而在iterator模式一文的例子中,午餐餐馆的菜单是通过数组实现的,为了继续使用数组实现,我们将CompositeMenu拷贝一份为CompositeMenu_ArrayVer,并修改相关实现细节
注意到CompositeMenu_ArrayVer中的createIterator方法从数组对象中返回一个迭代器,因此参考iterator模式一文中的PancakeMenuIterator,拷贝一份为GetMyItrFromArray
修改CompositeIterator对新的CompositeMenu_ArrayVer聚合对象做适配
Waitress类的printVegetarinMenu()方法适当修改
然后在main函数中进行测试
层次结构:
notion image
代码
结果
通过上面,就完成了composite模式与iterator模式的结合。
 
参考文章:
 
Linux上一些奇技淫巧Composite模式概念
Loading...