组合模式未直接解析Java Collection体系,但其“统一个体与容器操作”思想解释了Collection接口的统一性;Collection虽不提供树形管理方法,却通过add()、size()等契约践行组合精神,而真正需要嵌套语义时需自定义Composite结构。

组合模式本身并不直接解析 Java 的 Collection 体系,它和 Collection 接口及其子类(如 ArrayList、LinkedList)没有继承或实现关系。但它的设计思想——“统一个体与容器的操作”——恰好能帮你理解为什么 Collection 体系在使用上如此一致,也反向说明:Java 集合框架虽未按组合模式严格建模,却在接口契约层面践行了其核心精神。
为什么 Collection 接口天然体现组合模式逻辑
Collection 是所有单元素集合(如 HashSet)和可嵌套结构(如树形集合的自定义实现)的统一入口。它不区分“你存的是一个对象”还是“你存的是一个装满对象的容器”,只要实现了该接口,就能调用 add()、size()、iterator() 等方法:
-
个体变量(如单个
String)通过add("hello")加入集合,是“叶子”语义 -
容器对象(如另一个
Collection)也可被整体加入:mainList.addAll(anotherList),此时它作为“子组合”参与操作 - 客户端代码无需判断
anotherList是ArrayList还是TreeSet,更不用管它内部是否嵌套了其他集合——只要它是Collection,就支持统一遍历与聚合
Collection 体系未采用标准 Composite 结构的原因
标准组合模式要求 Component 明确定义 addChild()、getChild() 等树形管理方法,而 Collection 接口只关注“容纳元素”这一行为,并不承诺层级关系或递归结构:
-
Collection不提供addSubCollection()或getChildren()方法,它不负责构建树,只负责扁平化存储 - 像
TreeSet或ConcurrentSkipListSet虽内部用树实现,但对外仍表现为线性集合,不暴露父子节点概念 - 真正需要组合模式的场景(如文件系统、UI组件树),开发者会自己定义
FileSystemItem或UIComponent接口,而非复用Collection
何时该自己实现 Composite,而不是依赖 Collection
当你面对的数据具有明确的“部分-整体”嵌套语义,且需对整棵树做统一操作时,Collection 就不够用了,必须手写组合结构:
- 要计算一个目录总大小,需递归调用每个子文件夹的
size(),而不仅仅是遍历List<file></file> - 要禁用整个菜单栏,包括所有子菜单和菜单项,不能只对
List<menuitem></menuitem>调用setEnabled(false),因为子菜单本身也是可禁用的容器 - 要序列化/渲染一棵组织架构图,员工(Leaf)和部门(Composite)必须共享同一接口,才能被同一个遍历器处理
Collection 和 Composite 的协作方式
实际开发中,二者常配合使用:用 Collection 存储子节点列表,用自定义 Composite 类封装树形逻辑:
-
Composite类内部通常持有一个Collection<component></component>字段(如private List<component> children = new ArrayList();</component>) - 添加子节点调用
children.add(child),删除调用children.remove(child),这正是借用了Collection的成熟能力 - 但关键的
operation()行为(如draw()、getSize())由Composite自己递归实现,不依赖Collection接口

















