设计模式之组合模式 概述组合模式Composite Pattern是一种结构型设计模式它允许你将对象组合成树形结构来表示“部分 - 整体”的层次结构。组合模式使得客户端对单个对象和组合对象的使用具有一致性。简单来说就是让用户在使用单个对象和组合对象时无需区分它们就像操作同一个类型的对象一样。核心思想统一接口为单个对象叶子节点和组合对象容器节点定义统一的接口。树形结构通过递归组合形成树状结构。透明性客户端无需关心操作的是单个对象还是组合对象。适用场景你想要表示对象的部分 - 整体层次结构如文件系统、组织架构、菜单系统。你希望客户端忽略组合对象与单个对象的差异统一处理。你需要递归地处理树形结构中的节点。典型例子文件系统文件是叶子文件夹是组合GUI 组件按钮是叶子面板是组合公司组织架构员工是叶子部门是组合菜单系统菜单项是叶子子菜单是组合角色定义组合模式通常包含以下三个角色Component抽象组件声明所有具体组件包括叶子和组合的公共接口。可选定义默认行为或管理子组件的接口如add,remove,getChild。Leaf叶子节点代表树形结构中的叶节点没有子节点。实现 Component 接口提供具体业务逻辑。Composite组合节点代表有子节点的容器节点。实现 Component 接口并维护子组件集合。通常实现add,remove,getChild等方法并递归调用子组件的方法。Java 代码实现下面以“公司组织架构”为例演示组合模式的实现。定义抽象组件Componentimportjava.util.List;// Component: 抽象员工类publicabstractclassEmployee{protectedStringname;protectedStringposition;protecteddoublesalary;publicEmployee(Stringname,Stringposition,doublesalary){this.namename;this.positionposition;this.salarysalary;}// 添加员工默认不支持由叶子节点抛出异常或忽略publicvoidadd(Employeeemployee){thrownewUnsupportedOperationException(叶子节点不支持添加操作);}// 移除员工publicvoidremove(Employeeemployee){thrownewUnsupportedOperationException(叶子节点不支持移除操作);}// 获取子员工列表publicListEmployeegetChildren(){thrownewUnsupportedOperationException(叶子节点没有子节点);}// 显示信息publicabstractvoidshowDetails();// 计算总薪资递归publicdoublegetTotalSalary(){returnsalary;}}实现叶子节点Leaf// Leaf: 普通员工publicclassDeveloperextendsEmployee{publicDeveloper(Stringname,Stringposition,doublesalary){super(name,position,salary);}OverridepublicvoidshowDetails(){System.out.println(开发者: name, 职位: position, 薪资: salary);}// 叶子节点不需要重写 getTotalSalary使用父类默认实现即可}实现组合节点Compositeimportjava.util.ArrayList;importjava.util.List;// Composite: 经理可管理多个员工publicclassManagerextendsEmployee{privateListEmployeesubordinatesnewArrayList();publicManager(Stringname,Stringposition,doublesalary){super(name,position,salary);}Overridepublicvoidadd(Employeeemployee){subordinates.add(employee);}Overridepublicvoidremove(Employeeemployee){subordinates.remove(employee);}OverridepublicListEmployeegetChildren(){returnnewArrayList(subordinates);}OverridepublicvoidshowDetails(){System.out.println(经理: name, 职位: position, 薪资: salary);for(Employeeemp:subordinates){emp.showDetails();}}OverridepublicdoublegetTotalSalary(){doubletotalsalary;for(Employeeemp:subordinates){totalemp.getTotalSalary();}returntotal;}}客户端测试代码publicclassClient{publicstaticvoidmain(String[]args){// 创建叶子节点Developerdev1newDeveloper(张三,初级开发,8000);Developerdev2newDeveloper(李四,高级开发,12000);Developerdev3newDeveloper(王五,前端开发,9000);// 创建组合节点ManagertechLeadnewManager(赵六,技术主管,20000);ManagerctonewManager(钱七,CTO,50000);// 构建树形结构techLead.add(dev1);techLead.add(dev2);cto.add(techLead);cto.add(dev3);// 统一处理客户端无需区分是经理还是开发者System.out.println( 组织架构图 );cto.showDetails();System.out.println(\n 总薪资计算 );System.out.println(公司总薪资: cto.getTotalSalary());}}输出示例 组织架构图 经理: 钱七, 职位: CTO, 薪资: 50000.0 经理: 赵六, 职位: 技术主管, 薪资: 20000.0 开发者: 张三, 职位: 初级开发, 薪资: 8000.0 开发者: 李四, 职位: 高级开发, 薪资: 12000.0 开发者: 王五, 职位: 前端开发, 薪资: 9000.0 总薪资计算 公司总薪资: 99000.0优缺点分析优点一致性客户端可以一致地处理单个对象和组合对象简化了客户端代码。易于扩展新增叶子或组合类只需实现 Component 接口符合开闭原则。递归处理方便天然支持树形结构的递归操作如遍历、统计等。缺点设计复杂需要仔细设计抽象组件接口尤其是当叶子和组合的行为差异较大时。类型不安全在抽象组件中定义add/remove方法对叶子节点来说可能无意义虽然可以通过抛异常处理但不够优雅。难以限制组件类型组合节点可能包含任意类型的 Component缺乏类型约束。变体与安全式组合为了解决“类型不安全”的问题可以采用安全式组合模式将add,remove,getChild等方法只定义在Composite类中不在Component抽象类中定义。缺点客户端需要判断对象类型才能调用这些方法牺牲了一部分透明性。选择哪种方式取决于具体需求追求透明性→ 透明式组合上述示例追求类型安全→ 安全式组合总结组合模式是处理树形结构的利器它通过统一接口让客户端忽略单个对象和组合对象的差异极大地简化了代码结构。在文件系统、UI 框架、组织架构等场景中应用广泛。关键记忆点“部分 - 整体”结构 统一接口 递归处理 组合模式在使用时需权衡“透明性”与“类型安全”根据实际需求选择透明式或安全式设计。建议实践尝试用组合模式实现一个简单的菜单系统或文件系统模拟器加深理解。