什么是组合模式?
组合模式是一种结构型设计模式,它允许你将对象组合成树形结构来表示"部分-整体"的层次关系。组合模式使得客户端对单个对象和组合对象的使用具有一致性。
组合模式包含以下角色:
- 组件(Component):声明组合中对象的接口,适当情况下实现所有类共有接口的默认行为
- 叶子(Leaf):表示叶子节点对象,没有子节点
- 复合节点(Composite):定义有子部件的部件行为,存储子部件,并在Component接口中实现与子部件有关的操作
- 客户端(Client):通过Component接口操作组合部件的对象
组合模式的优缺点
优点:
- 统一处理:客户端可以一致地使用组合结构和单个对象
- 灵活性:容易增加新的组件类型,符合开闭原则
- 简化客户端代码:客户端不需要区分叶子节点和组合节点
- 层次结构清晰:能够清晰地表示对象之间的层次关系
缺点:
- 设计复杂:系统中存在大量小对象,系统更复杂
- 难以限制容器中的构件:很难限制组合中的构件类型
- 不易控制构件类型:不容易用继承的方法来增加新的行为
什么场景下使组合模式
- 表示对象的部分-整体层次结构
- 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象
- 需要遍历组织机构树、文件系统、菜单系统等树形结构
- 需要动态地组合对象,形成复杂的层次结构
代码举例
下面是以组织架构为例子
// 组件接口 - 员工组件
abstract class EmployeeComponent {protected String name;protected String position;public EmployeeComponent(String name, String position) {this.name = name;this.position = position;}public String getName() {return name;}public String getPosition() {return position;}// 抽象方法public abstract void display(int depth);public abstract double getSalary();public abstract int getEmployeeCount();public abstract double getTotalSalary();// 默认实现public boolean add(EmployeeComponent employee) {throw new UnsupportedOperationException("不支持添加员工");}public boolean remove(EmployeeComponent employee) {throw new UnsupportedOperationException("不支持删除员工");}public List<EmployeeComponent> getSubordinates() {throw new UnsupportedOperationException("不支持获取下属");}
}// 叶子节点 - 普通员工
class Employee extends EmployeeComponent {private double salary;public Employee(String name, String position, double salary) {super(name, position);this.salary = salary;}@Overridepublic void display(int depth) {String indent = " ".repeat(depth);System.out.println(indent + "👤 " + name + " - " + position + " (薪资: ¥" + salary + ")");}@Overridepublic double getSalary() {return salary;}@Overridepublic int getEmployeeCount() {return 1;}@Overridepublic double getTotalSalary() {return salary;}
}// 复合节点 - 管理者
class Manager extends EmployeeComponent {private double baseSalary;private List<EmployeeComponent> subordinates = new ArrayList<>();public Manager(String name, String position, double baseSalary) {super(name, position);this.baseSalary = baseSalary;}@Overridepublic boolean add(EmployeeComponent employee) {return subordinates.add(employee);}@Overridepublic boolean remove(EmployeeComponent employee) {return subordinates.remove(employee);}@Overridepublic List<EmployeeComponent> getSubordinates() {return new ArrayList<>(subordinates);}@Overridepublic void display(int depth) {String indent = " ".repeat(depth);System.out.println(indent + "💼 " + name + " - " + position + " (基本薪资: ¥" + baseSalary + ", 下属: " + subordinates.size() + "人)");for (EmployeeComponent subordinate : subordinates) {subordinate.display(depth + 1);}}@Overridepublic double getSalary() {return baseSalary;}@Overridepublic int getEmployeeCount() {int count = 1; // 包括自己for (EmployeeComponent subordinate : subordinates) {count += subordinate.getEmployeeCount();}return count;}@Overridepublic double getTotalSalary() {double total = baseSalary;for (EmployeeComponent subordinate : subordinates) {total += subordinate.getTotalSalary();}return total;}// 获取特定职位的员工public List<EmployeeComponent> getEmployeesByPosition(String position) {List<EmployeeComponent> result = new ArrayList<>();collectEmployeesByPosition(position, result);return result;}private void collectEmployeesByPosition(String targetPosition, List<EmployeeComponent> result) {if (this.position.equals(targetPosition)) {result.add(this);}for (EmployeeComponent subordinate : subordinates) {if (subordinate.getPosition().equals(targetPosition)) {result.add(subordinate);}if (subordinate instanceof Manager) {((Manager) subordinate).collectEmployeesByPosition(targetPosition, result);}}}
}// 客户端使用示例
public class OrganizationDemo {public static void main(String[] args) {// 创建CEOManager ceo = new Manager("张三", "CEO", 100000);// 创建部门经理Manager cto = new Manager("李四", "CTO", 80000);Manager cfo = new Manager("王五", "CFO", 75000);Manager hrManager = new Manager("赵六", "HR经理", 60000);// 创建技术团队Manager techManager = new Manager("钱七", "技术经理", 50000);Employee developer1 = new Employee("孙八", "高级开发工程师", 35000);Employee developer2 = new Employee("周九", "中级开发工程师", 25000);Employee developer3 = new Employee("吴十", "初级开发工程师", 18000);Employee qaEngineer = new Employee("郑一", "测试工程师", 22000);// 创建财务团队Employee accountant1 = new Employee("王二", "高级会计师", 28000);Employee accountant2 = new Employee("冯三", "会计师", 22000);// 创建HR团队Employee recruiter = new Employee("陈四", "招聘专员", 18000);Employee trainer = new Employee("褚五", "培训专员", 16000);// 构建组织架构// CEO下属ceo.add(cto);ceo.add(cfo);ceo.add(hrManager);// CTO下属cto.add(techManager);cto.add(qaEngineer);// 技术经理下属techManager.add(developer1);techManager.add(developer2);techManager.add(developer3);// CFO下属cfo.add(accountant1);cfo.add(accountant2);// HR经理下属hrManager.add(recruiter);hrManager.add(trainer);// 显示组织架构System.out.println("=== 公司组织架构 ===");ceo.display(0);// 统计信息System.out.println("\n=== 组织统计 ===");System.out.println("总员工数: " + ceo.getEmployeeCount() + "人");System.out.println("总薪资支出: ¥" + ceo.getTotalSalary());// 查找特定职位System.out.println("\n=== 开发工程师列表 ===");List<EmployeeComponent> developers = ceo.getEmployeesByPosition("中级开发工程师");for (EmployeeComponent dev : developers) {System.out.println("- " + dev.getName() + " (" + dev.getPosition() + ")");}}
}