引入
文件夹对我们来说很熟悉,文件夹里面可以包含文件夹,也可以包含文件。
那么文件夹是个容器,文件夹里面的文件夹也是个容器,文件夹里面的文件是对象。
1303036-20190814155518657-1945436691.png
这是个树型结构,生活中常用的一种结构。
文件是一个简单的对象,我们直接打开就可以使用。文件夹是一个复杂的对象,因为里面还有子文件夹或者文件。我们在使用文件夹时用相同的方式对待文件夹和文件。其实这时候我们就是在使用设计模式中的组合模式。
另外公司的组织结构也是常用的树型结构,也适合使用组合模式
1303036-20190814161010812-591591436.png
组合模式定义
组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树型结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树型结构。
这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。
使用场景
- 想表示对象的部分-整体层次结构(树型结构)
- 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构
- 如果你想要创建层次结构,并可以在其中以相同的方式对待所有元素,那么组合模式就是最理想的选择
涉及角色
- Component 是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理(Component)子部件
- Leaf 在组合中表示叶子结点对象,叶子结点没有子结点
- Composite 定义有枝结点行为,用来存储子部件,在Component 接口中实现与子部件有关操作,如增加和删除等
组合模式的优点
- 组合模式可以清楚地定义分成次的复杂对象,表示对象的全部和部分层次,它让客户端忽略了层次的差异,方便对整个层次结构进行控制。
- 客户端可以一致地使用组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码。
- 在组合模式中增加新的容器构件和叶子构件都很方便,无需对现有类库进行任何修改,符合"开闭原则"。
- 组合模式为树型结构的面向 对象实现提供了一种灵活的解决方案,通过叶子对象和容器对象的递归组合,可以形成复杂的树型结构,但对树型结构的控制却非常简单。
组合模式的缺点
在增加新构件时很难对容器中的构件类型进行限制。有时候我们希望一个容器中只能有某些特定类型的对象,例如在某个文件夹中只能包含文件,使用组合模式时,不能依赖类型系统来施加这些约束,因为它们都来自于相同的抽象层,在这情况下,必须通过在运行时进行类型检查来实现,这个实现过程较为复杂。
组合模式有两种
(1)透明组合模式
透明组合模式中,抽象构件(Component)中声明了所有管理成员对象的方法,包括 add(), remove() 以及 getChild()等方法,这样做的好处是确保所有的构件类都有相同的接口。在客户端看来,叶子对象与容器对象所提供的方法是一致的,客户端可以相同地对待所有对象。透明组合模式也是组合模式的标准形式。
透明组合模式的缺点就是不够安全,因为叶子对象和容器对象在本质上是有区别的。叶子对象不可能有下一个层次的对象,即不可能包含成员对象,因此为其提供add(),remove()以及getChild()等方法是没有意义的,这在编译阶段不会出错,但在运行阶段如果调用这些方法可能会出错(如果没提供相应的错误处理代码)。
(2)安全组合模式
安全组合模式中,在抽象构件(Component)中没有声明任何用于管理成员对象的方法,而是在Composite类中声明并实现这些方法。这种做法是安全的,因为根本不向叶子对象提供这些管理成员对象的方法,对于叶子对象,客户端不可能调用到这些方法。
安全组合模式的缺点是不够透明,因为叶子构件和容器构件具有不同的方法,且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义,因此客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件。在实际应用中,安全组合模式的使用频率也非常高,在Java AWT 中使用的组合模式就是安全组合模式。
示例代码
# 抽象一个组织类
class Component:
def __init__(self, name):
self.name = name
def add(self, comp):
pass
def remove(self, comp):
pass
def display(self, depth):
pass
# 叶子结点
class Leaf(Component):
def add(self):
print("不能添加子结点")
def remove(self):
print("不能删除子结点")
def display(self, depth):
strtemp = ''
for i in range(depth):
strtemp += "----"
print(strtemp + self.name)
# 枝结点
class composite(Component):
def __init__(self, name):
self.name = name
self.children = []
def add(self, comp):
self.children.append(comp)
def remove(self, comp):
self.children.remove(comp)
def display(self, depth):
strtemp = ''
for i in range(depth):
strtemp += "----"
print(strtemp + self.name)
for comp in self.children:
comp.display(depth + 2)
if __name__ == "__main__":
root=Composite('根')
root.add(Leaf('叶1a'))
root.add(Leaf('叶1b'))
root.add(Leaf('花1a'))
root.add(Leaf('花1b'))
comp1a=Composite('枝1a')
comp1b=Composite('枝1b')
root.add(comp1a)
root.add(comp1b)
comp1a.add(Leaf('叶2a'))
comp1a.add(Leaf('叶2b'))
comp1a.add(Leaf('花2a'))
comp1a.add(Leaf('花2b'))
comp2a=Composite('枝2a')
comp1a.add(comp2a)
comp1b.add(Leaf('叶2a'))
comp1b.add(Leaf('花2a'))
comp2a.add(Leaf('叶3a'))
comp2a.add(Leaf('花3a'))
comp3a=Composite('枝3a')
comp2a.add(comp3a)
comp3a.add(Leaf('叶4a'))
comp3a.add(Leaf('花4a'))
root.display(1)
···
网友评论