什么是组合模式?
组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。掌握组合模式的重点是要理解清楚 “部分/整体” 还有 ”单个对象“ 与 “组合对象” 的含义。
组合模式UML图
组合模式python实现
下面考虑一个目录的例子:
题目:
一个目录,目录下可以有子目录和具体文件(叶节点),子目录和目录的行为方法相同对外界有相同的接口
题目分析:
对于子目录和目录,即整体和部分可以被一致对待。
当需求中是体现部分与整体层次结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一的使用组合结构中的所有对象时,就应该考虑组合模式。组合模式是将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使用户对单个对象和组合对象的使用具有一致性。
python 代码实现
Catalog类:
class Catalog():
def __init__(self,name):
self.name = name #目录的名字
self.children = [] #子节点列表
#向该目录下添加一个目录或叶节点
def add(self,leaf):
self.children.append(leaf)
#以字符串为名字的节点是否在子节点列表中,若在返回下标,不在返回-1
def name_in(self,name):
for i in range(len(self.children)):
child = self.children[i]
if name == child.name:
return i
return -1
#删除该目录下的以leaf_name为名字的子节点,若无抛出异常
def delete(self,leaf_name):
index = self.name_in(leaf_name)
if index >= 0:
del self.children[index]
else:
raise Exception("Catalog without the deleted items")
#展示树形结构
def display(self,depth):
print '-'*depth + self.name
for child in self.children:
child.display(depth+2)
Leaf类:
class Leaves(Catalog):
def __init__(self,name='',value=''):
self.name = name
self.children = []
self.value = value #叶节点的值
#若向叶节点添加目录或叶节点抛出异常
def add(self,leaf):
raise Exception("Leaf nodes can't insert catalog")
#想在叶节点下访问子节点列表,抛出异常
def name_in(self,name):
raise Exception("Leaf nodes without subcatalog")
#想在叶节点下访问子节点列表,抛出异常
def delete(self,leaf_name):
raise Exception("Leaf nodes without subcatalog")
测试:
>>> from Catalog import Catalog,Leaves
>>> root = Catalog("root")
>>> SubCatalog1 = Catalog("SubCatalog1")
>>> SubCatalog2 = Catalog("SubCatalog2")
>>> leaf1 = Leaves("leaf1","1")
>>> leaf2 = Leaves("leaf2","2")
>>> leaf3 = Leaves("leaf3","3")
>>> leaf4 = Leaves("leaf4","4")
>>> root.add(SubCatalog1)
>>> root.add(SubCatalog2)
>>> root.add(leaf1)
>>> SubCatalog1.add(leaf2)
>>> SubCatalog1.add(leaf3)
>>> SubCatalog2.add(leaf4)
>>> root.display(0)
root
--SubCatalog1
----leaf2
----leaf3
--SubCatalog2
----leaf4
--leaf1
>>> SubCatalog2.delete("leaf4")
>>> root.display(0)
root
--SubCatalog1
----leaf2
----leaf3
--SubCatalog2
--leaf1
>>> SubCatalog2.delete("leaf4")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "Catalog.py", line 20, in delete
raise Exception("Catalog without the deleted items")
Exception: Catalog without the deleted items
>>> root.display(0)
root
--SubCatalog1
----leaf2
----leaf3
--SubCatalog2
--leaf1
>>> new_leaf1 = Leaves("new_leaf1","1")
>>> new_leaf2 = Leaves("new_leaf2","2")
>>> leaf1.add(new_leaf1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "Catalog.py", line 31, in add
raise Exception("Leaf nodes can't insert catalog")
Exception: Leaf nodes can't insert catalog
>>> leaf1.delete("new_leaf1")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "Catalog.py", line 35, in delete
raise Exception("Leaf nodes without subcatalog")
Exception: Leaf nodes without subcatalog
>>> SubCatalog2.add(new_leaf1)
>>> SubCatalog2.add(new_leaf2)
>>> root.display(0)
root
--SubCatalog1
----leaf2
----leaf3
--SubCatalog2
----new_leaf1
----new_leaf2
--leaf1
>>> root.delete("SubCatalog2")
>>> root.display(0)
root
--SubCatalog1
----leaf2
----leaf3
--leaf1
透明组合模式与安全组合模式
透明方式
在Component中声明所有用来管理子对象的方法,如Add()方法,delete()方法及name_in()方法,所有实现Component接口的子类都具备这些方法,这使得Component和子类具备一致的行为接口,使得对客户端无需区别树叶和树枝对象。
正由于我们的Composite和Leaf都具备一致的接口行为,但我们知道Leaf不应该具有Add(),delete()及name_in()方法,因为我们叶子节点不能再添加和移除节点了。
安全模式
在透明模式基础上把Component中声明所有用来管理子对象的方法移到Composite中,在Composite实现子对象的管理方法,那么Leaf就没有子对象管理方法,这使得Composite和Leaf的行为接口不一致,所以客户端在调用时要知道树叶和树枝对象存在。
两种组合模式各有好处,具体使用视情况而定