【西瓜带你学设计模式 | 第十三期 - 组合模式】组合模式 —— 树形结构统一处理实现、优缺点与适用场景

张开发
2026/4/10 6:41:23 15 分钟阅读

分享文章

【西瓜带你学设计模式 | 第十三期 - 组合模式】组合模式 —— 树形结构统一处理实现、优缺点与适用场景
文章目录前言1. 组合模式是什么2. 组合模式解决什么问题3. 核心结构3.1 Component抽象组件3.2 Leaf叶子节点3.3 Composite组合节点 / 容器节点3.4 Client客户端4. 实现思路递归 统一接口5. 示例5.1 Component文件系统项5.2 Leaf文件5.3 Composite文件夹5.4 Client构建树并统一调用6. 优缺点6.1 优点6.2 缺点7. 和其他设计模式区别7.1 组合模式 vs 装饰器7.2 组合模式 vs 外观7.3 组合模式 vs 代理8. 适用场景9. 总结前言很多业务天生就是“树形结构 / 部分-整体层次关系”文件系统文件 文件夹文件夹还能再装文件夹组织架构部门可包含子部门 员工菜单主菜单 子菜单GUI 组件树面板容器里有按钮、面板里又有面板如果用“分类型处理”的方式叶子一个逻辑、容器另一个逻辑客户端代码会越来越难维护。组合模式正是为了解决这种“层次结构要统一处理”的问题让客户端把“单个对象”和“对象组合容器”当成同一种类型来用从而统一操作整棵树。1. 组合模式是什么组合模式Composite Pattern是一种结构型设计模式。它允许你把对象组织成树形结构表示“部分-整体”的层次结构并让客户端以一致的方式处理叶子节点Leaf最小单元组合节点Composite可以包含子节点叶子或其它组合一句话定义理解用像处理单个文件一样处理文件夹整棵结构。2. 组合模式解决什么问题组合模式主要解决这类问题当系统存在复杂层次结构例如文件夹/文件时如果你对“叶子”和“容器”分开写逻辑会造成重复代码、维护成本高客户端需要频繁判断类型instanceof / 强转难以扩展新的层次节点组合模式的核心解决方案是定义统一接口 Component让叶子与容器都实现它。客户端只依赖 Component通过递归处理树形结构。3. 核心结构3.1 Component抽象组件定义“所有节点都要支持的公共接口”例如display()/operation()对于“管理子节点”的方法可能有两种风格透明模式Component 里也声明add/remove叶子节点可能抛异常或空实现安全模式Component 只声明业务方法子节点管理只放在 Composite3.2 Leaf叶子节点树的末端节点没有子节点实现 Component 的业务方法3.3 Composite组合节点 / 容器节点同样实现 Component内部持有ListComponent或其它集合支持add/remove业务方法里会递归调用子节点的业务方法3.4 Client客户端面向Component编程不关心当前节点是 Leaf 还是 Composite直接对整棵树调用同一个接口方法4. 实现思路递归 统一接口实现时一般遵循抽象出公共接口Component业务方法写Leaf只处理自己的业务写Composite维护 children并在业务方法里遍历递归调用客户端只拿到一个 rootComponent直接调用即可5. 示例下面用“文件系统”作为例子File是叶子节点Folder是组合节点客户端只通过display()操作整棵树不用管文件还是文件夹5.1 Component文件系统项publicinterfaceFileSystemComponent{voiddisplay();}5.2 Leaf文件publicclassFileimplementsFileSystemComponent{privatefinalStringname;publicFile(Stringname){this.namename;}Overridepublicvoiddisplay(){System.out.println(文件: name);}}5.3 Composite文件夹importjava.util.ArrayList;importjava.util.List;publicclassFolderimplementsFileSystemComponent{privatefinalStringname;privatefinalListFileSystemComponentchildrennewArrayList();publicFolder(Stringname){this.namename;}publicvoidadd(FileSystemComponentcomponent){children.add(component);}Overridepublicvoiddisplay(){System.out.println(文件夹: name);for(FileSystemComponentchild:children){child.display();// 关键递归统一处理}}}5.4 Client构建树并统一调用publicclassClient{publicstaticvoidmain(String[]args){FileSystemComponentdocnewFolder(文档目录);((Folder)doc).add(newFile(doc1.txt));((Folder)doc).add(newFile(doc2.txt));FileSystemComponentrootnewFolder(根目录);((Folder)root).add(doc);((Folder)root).add(newFile(readme.md));root.display();}}运行效果类似先打印根目录组合节点再递归打印其下的子节点叶子/组合都一样走display()6. 优缺点6.1 优点统一接口客户端对叶子/容器用同样的方式处理结构清晰天然表达“部分-整体”的层次关系扩展性强新增节点类型通常不会破坏客户端继续实现 Component递归自然遍历整棵树、计算总量、渲染结构都很顺畅6.2 缺点实现复杂度可能上升尤其当树很深或节点类型很多时透明模式风险若在 Component 放了add/removeLeaf 可能只能空实现或抛异常性能/递归开销遍历或计算可能带来额外开销树很大时更明显7. 和其他设计模式区别7.1 组合模式 vs 装饰器组合模式在“结构上”把对象组织成树强调整体-部分与递归处理装饰器模式在“对象上”动态加行为强调包装叠加功能通常是一条调用链一句话组合模式是“树结构的统一处理”装饰器是“包装增强同一对象”。7.2 组合模式 vs 外观外观模式提供一个简单入口隐藏复杂子系统“封装入口”组合模式表达层次结构让客户端递归地对节点统一操作“表示结构”7.3 组合模式 vs 代理代理模式控制访问/转发权限、远程对象、延迟加载等组合模式管理层级关系与统一遍历调用8. 适用场景组合模式特别适合需要表达树形结构或部分-整体层次希望客户端代码能统一处理叶子与容器需要对整棵结构做递归操作遍历、渲染、计算汇总等结构可能会动态变化节点增删9. 总结把对象组织成树形结构让叶子和容器实现统一接口客户端对它们用同一种方式处理并通过递归完成整体操作。

更多文章