组合模式
组合模式是一种结构型设计模式,用于将对象组合成树形结构以表示“部分-整体”的层次关系。使得客户端能够以统一的方式处理单个对象和组合对象
特点
- 统一接口:客户端无需区分操作的是单个对象还是组合对象。
- 递归结构:组合对象可以嵌套其他组合对象或者叶子节点,形成树形结构。
- 透明性:所有的方法都在已抽象组件中声明
- 动态拓展:新增组件类型时,无需修改现有代码
模式结构
角色 | 描述 |
---|---|
抽象组件 (Component) | 定义组合对象和叶子对象的共有接口,声明管理叶子组件的方法。 |
叶子 (Leaf) | 定义叶子对象(无子节点)的行为,实现抽象组件所声明的接口。 |
组合 (Composite) | 定义组合对象(包含子组件的复杂对象)的行为,实现抽象组件所声明的接口。 |
简单示例
from abc import ABC, abstractmethod
from typing import List
# 抽象组件
class FileSystem(ABC):
@abstractmethod
def display(self, indent: int=0) -> None: pass
def add(self, Composite: 'FileSystem') -> None:
raise NotImplementedError("叶子节点不支持添加子节点")
def remove(self, Composite: 'FileSystem') -> None:
raise NotImplementedError("叶子节点不支持删除子节点")
# 叶子节点
class File(FileSystem):
def __init__(self, name: str) -> None:
self.name = name
def display(self, indent: int=0) -> None:
print("| " * indent + "|--" + self.name)
# 叶子节点的其他方法已经在抽象组件中声明
# 组合节点
class Directory(FileSystem):
def __init__(self, name: str) -> None:
self.name = name
self.children: List[FileSystem] = []
def display(self, indent: int=0) -> None:
print("| " * indent + "|--" + self.name)
for child in self.children:
child.display(indent + 1)
def add(self, child: FileSystem) -> None:
self.children.append(child)
def remove(self, child: FileSystem) -> None:
self.children.remove(child)
# 客户端使用
if __name__ == "__main__":
root = Directory("root")
tmp = Directory("tmp")
bin = Directory("bin")
root.add(tmp)
root.add(bin)
file1 = File("file1.txt")
file2 = File("file2.txt")
tmp.add(file1)
bin.add(file2)
root.display()
# |--root
# | |--tmp
# | | |--file1.txt
# | |--bin
# | | |--file2.txt
bin.remove(file2)
root.display()
# |--root
# | |--tmp
# | | |--file1.txt
# | |--bin
优缺点
- 优点
- 支持递归操作,即对树形结构可以进行统一的处理
- 灵活拓展新组件类型
- 简化客户端的使用,全部都是统一接口
- 缺点
- 透明式设计在叶子节点上可能未实现某些操作导致运行错误
- 组合层次过深时调试困难
使用场景
- 菜单栏(菜单项和子菜单)
- 文件系统(文件夹和文件)
- 组织架构(部门和员工)