Java中对象组合通过“整体-部分”树形结构建模业务层级关系,以统一接口(Component)定义行为,叶子节点(Leaf)专注自身逻辑,组合节点(Composite)委托子组件实现,确保调用一致且易于扩展。

Java 中通过对象组合表达业务关系,核心是用“整体-部分”的树形结构建模现实中的层级依赖,而不是靠继承或硬编码关联。关键不在于堆砌类,而在于让不同粒度的对象(比如一个员工、一个部门、整个公司)能被统一操作。
用组合接口统一行为
定义一个抽象组件(Component),声明所有对象共有的业务方法,比如 print()、getCost()、countMembers()。这个接口不暴露“是不是容器”这种细节,只说“你能做什么”。
叶子节点(Leaf)实现它,专注自身逻辑——例如一个 SalesEmployee 类,countMembers() 就返回 1,getCost() 返回工资。
组合节点(Composite)也实现它,但内部持有一组子组件,并把业务委托给它们——比如 Department 的 countMembers() 是遍历所有子部门和员工,累加各自 countMembers() 的结果。
这样,调用方写 dept.print() 或 emp.print(),代码完全一样;新增一个 Contractor 类,只要实现 Component 接口,现有统计、展示、导出等逻辑全都不用改。
按业务语义组织子节点
组合不是随便套娃,得符合业务规则。例如:
- 公司 → 部门 → 小组 → 员工:每个层级职责清晰,小组不能包含部门,员工不能添加子项
- 订单 → 订单项 → 商品 + 优惠券:订单项是组合节点,商品和优惠券是叶子,但两者类型不同,可共用
calculateAmount()接口 - 文档系统 → 文件夹 → 子文件夹 / 文档 / 图片:文件夹管理子项,文档只提供内容读取
重点是:哪些对象该有子项、哪些不该,由业务决定,不是技术强行统一。叶子类里对 add()、remove() 抛 UnsupportedOperationException 不是缺陷,而是明确边界。
避免两种常见偏差
- 不要把组合当成“为了设计模式而组合”:如果业务中根本不存在层级(比如用户和地址只是 1:1 关联,地址不会嵌套地址),用普通字段引用更自然
- 不要混淆组合与聚合:组合强调强生命周期依赖(部门删了,下属员工对象也应失效),聚合更松散(订单删了,商品信息仍独立存在)。Java 里都用字段引用,区别在语义和销毁逻辑,不在语法
本质上,对象组合表达业务关系,就是把“谁属于谁”“谁管谁”“谁能执行什么操作”这些现实约束,翻译成一组共享接口 + 明确职责边界的类协作。写出来之后,看一眼 client.doSomething(root) 就能明白它既适用于单个对象,也适用于整棵树——那就到位了。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











