组合模式的核心作用是统一“单个对象”和“一堆对象”的调用方式,使树形结构操作自动递归到底层;适用于文件系统、组织架构、UI控件树、商品分类等具有“整体-部分”层级关系的场景。

组合模式的核心作用,就是让树形结构里的“单个对象”和“一堆对象”看起来一样,调用方式统一,操作自动向下递归到底层。
什么时候该用组合模式
当你面对的数据天然带层级、能拆成“整体-部分”关系时,组合模式就非常贴切。典型场景包括:
- 文件系统:文件夹(可含子文件夹或文件)和文件(末端)
- 组织架构:部门(含下级部门或员工)和员工(无下属)
- UI控件树:窗口(含按钮、文本框等子控件)和按钮(不可再嵌套控件)
- 商品分类:一级类目(如“服装”)→二级类目(如“男装”)→叶子类目(如“衬衣”)
三个关键角色怎么搭
组合模式靠三类角色协作,接口统一是前提:
-
Component(组件接口):声明所有节点共有的方法,比如
print()、getSize()、add()、remove()。它不关心自己是叶子还是容器,只管定义契约。 -
Leaf(叶子节点):实现 Component,但内部不存子节点。它的
print()直接输出自身信息;add()这类操作通常空实现或抛异常——因为它本就不该被添加子项。 -
Composite(组合节点):也实现 Component,但内部持有一个 Component 列表。它的
print()先输出自己,再遍历调用每个子节点的print();add()则把传入对象加进列表,并设置父引用(可选)。
递归操作是怎么自动发生的
关键在 Composite 的方法实现里嵌套调用子节点的同名方法。例如一个calculateTotalPrice():
- Leaf 返回自己商品的价格
- Composite 先累加自身价格(如有),再对每个 child 调用
calculateTotalPrice()并求和 - 客户端只需对根节点调一次,整棵树就自动算完了,不用写循环或手动判断类型
实际编码要注意什么
避免几个常见坑:
- Leaf 的管理方法(如
add/remove)别留空壳——建议抛UnsupportedOperationException或返回错误提示,防止误用 - Composite 中维护子节点时,注意是否要支持重复添加、是否需检查循环引用(比如把父节点加进子列表)
- 如果需要向上追溯(比如从叶子找根路径),可在 Component 中增加
getParent()并在 add 时自动设置 - 语言特性可简化实现:Go 用接口隐式实现、Python 用鸭子类型、Java/C++ 靠抽象类或纯虚函数约束
不复杂但容易忽略










