设计模式之组合模式¶
一个人几乎可以在任何他怀有无限热忱的事情上成功。
Author:李东阳
1、什么是组合模式¶
内容¶
将对象 组合成 树形结构 以表示“部分-整体”的层次结构。组合模式使得用户对 单个对象 和 组合对象 的使用 具有一致性。
角色¶
-
抽象组件(Component)
-
叶子组件(Leaf)
-
复合组件(Composite)
-
客户端(Client)
实际应用场景¶
-
组织结构:组合模式可以用于表示公司的组织结构,将公司分成多个部门,每个部门又包含多个小组,每个小组又包含多个员工。
-
文件系统:组合模式可以用于表示文件系统的层次结构,将文件系统分成多个文件夹,每个文件夹又包含多个子文件夹和文件。
-
图形用户界面:组合模式可以用于表示图形用户界面中的控件层次结构,将界面分成多个面板,每个面板又包含多个子控件。
-
产品配置:组合模式可以用于表示产品配置的层次结构,将产品分成多个组件,每个组件又包含多个子组件。
-
电子商务:组合模式可以用于表示电子商务网站中的商品分类,将商品分成多个分类,每个分类又包含多个子分类和商品。
2、组合模式的实现¶
from abc import ABCMeta, abstractmethod
# 抽象组件基类 接口
class Graphic(metaclass=ABCMeta):
@abstractmethod
def draw(self):
pass
# 叶子节点:不可再分,最底层
class Point(Graphic):
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"点({self.x},{self.y})"
def draw(self):
print(str(self))
# 复合节点:两个点p1、p2是线的子节点
class Line(Graphic):
def __init__(self, p1, p2):
self.p1 = p1
self.p2 = p2
def __str__(self):
return f"线段({self.p1},{self.p2})"
def draw(self):
print(str(self))
# 顶层复合节点:所有传入的iterable对象都是Picture对象子节点
class Picture(Graphic):
def __init__(self, iterable):
# 初始化对象时遍历iterable向Picture添加对象
self.children = []
for elem in iterable:
self.add(elem)
def add(self, graphic):
self.children.append(graphic)
def draw(self):
# 遍历运行每个对象的draw方法
for elem in self.children:
elem.draw()
# 客户端
if __name__ == "__main__":
# 组合pic1的树形对象组合
p1 = Point(0, 0)
l1 = Line(Point(1, 1), Point(2, 2))
l2 = Line(Point(3, 3), Point(4, 4))
pic1 = Picture([p1, l1, l2])
# 组合pic2的树形对象组合
p2 = Point(5, 5)
l3 = Line(Point(6, 6), Point(7, 7))
pic2 = Picture([p2, l3])
# 组合pic树形对象组合
pic = Picture([pic1, pic2])
# 递归的调用各个子对象的draw方法
pic.draw()
##########################################
# 输出:
点(0,0)
线段(点(1,1),点(2,2))
线段(点(3,3),点(4,4))
点(5,5)
线段(点(6,6),点(7,7))
# 可以看出,虽然我们是写了三个类,但是由于这三个类都实现了同接口,所以用户在使用这些类时会体会到他们的一致性
3、总结¶
优点¶
-
简化代码结构:通过将对象组合成树状结构,可以避免使用大量的if/else或switch语句来处理不同的对象类型,从而简化了代码结构。
-
增强代码可扩展性和可维护性:当需要添加新的节点类型时,只需要创建新的类实现相同的接口即可,而不需要修改现有的代码。这样可以增强代码的可扩展性和可维护性。
-
提高代码复用性:由于所有节点实现相同的接口,因此可以在不同的组合中重复使用相同的节点。
-
可以透明地处理组合对象和单个对象:客户端代码可以像处理单个对象一样处理组合对象和单个对象,无需关心对象的具体类型,从而实现了透明性。
-
可以提高代码的灵活性:由于组合模式中的对象都实现相同的接口,因此可以灵活地组合不同的对象实现不同的功能。
缺点¶
-
可能会导致设计过度复杂:当对象层次结构较为复杂时,使用组合模式可能会导致设计过度复杂,从而增加代码的维护成本。
-
可能会影响性能:由于组合模式需要遍历整个对象树才能执行某些操作,因此可能会影响程序的性能。
-
可能会限制对象的类型:由于组合模式要求所有节点实现相同的接口,因此可能会限制对象的类型。如果某些节点需要特定的方法或属性,则需要在接口中定义这些方法或属性,从而增加了接口的复杂度。