以下是一个结合组合模式解决实际开发问题的Java实现案例,涵盖树形结构处理、统一接口设计、递归操作优化等场景需求,附带逐行中文注释:
场景描述
实现一个企业组织架构管理系统,需满足:
树形结构:支持无限层级部门嵌套
统一操作:统计部门人数(含子部门)
动态增删:运行时修改组织架构
访问控制:不同部门有独立权限配置
性能优化:避免重复计算人员总数
完整代码实现:
import java.util.ArrayList;
import java.util.List;
/**
* 组织组件抽象类(Component)
*/
abstract class OrganizationComponent {
protected String name; // 部门/员工名称
protected String deptCode;// 部门编码(员工为null)
public OrganizationComponent(String name) {
this.name = name;
}
// 公共操作方法(默认抛出异常,叶子节点需覆盖)
public void add(OrganizationComponent component) {
throw new UnsupportedOperationException("当前节点不支持添加操作");
}
public void remove(OrganizationComponent component) {
throw new UnsupportedOperationException("当前节点不支持删除操作");
}
// 获取子节点(容器节点需实现)
public List<OrganizationComponent> getChildren() {
throw new UnsupportedOperationException("当前节点无子节点");
}
// 统计人数(抽象方法)
public abstract int countMembers();
// 打印结构(抽象方法)
public abstract void printStructure(int depth);
// 权限校验模板方法
public final boolean checkPermission(String permissionCode) {
// 1. 检查当前节点权限
if (hasLocalPermission(permissionCode)) return true;
// 2. 递归检查上级权限
return checkParentPermission(permissionCode);
}
// 当前节点权限校验(由子类实现)
protected abstract boolean hasLocalPermission(String permissionCode);
// 上级权限校验(由子类实现)
protected abstract boolean checkParentPermission(String permissionCode);
}
/**
* 部门类(Composite)
*/
class Department extends OrganizationComponent {
private List<OrganizationComponent> children = new ArrayList<>();
private int cachedMemberCount = -1; // 缓存人数(-1表示未缓存)
private String[] permissions; // 部门权限列表
public Department(String name, String deptCode, String[] permissions) {
super(name);
this.deptCode = deptCode;
this.permissions = permissions;
}
@Override
public void add(OrganizationComponent component) {
children.add(component);
invalidateCache(); // 增删操作后清除缓存
}
@Override
public void remove(OrganizationComponent component) {
children.remove(component);
invalidateCache();
}
@Override
public List<OrganizationComponent> getChildren() {
return new ArrayList<>(children); // 返回副本防止外部修改
}
@Override
public int countMembers() {
if (cachedMemberCount == -1) {
cachedMemberCount = children.stream()
.mapToInt(OrganizationComponent::countMembers)
.sum();
}
return cachedMemberCount;
}
@Override
public void printStructure(int depth) {
String indent = " ".repeat(depth);
System.out.printf("%s[部门] %s(%d人)%n",
indent, name, countMembers());
for (OrganizationComponent child : children) {
child.printStructure(depth + 1);
}
}
@Override
protected boolean hasLocalPermission(String permissionCode) {
for (String p : permissions) {
if (p.equals(permissionCode)) return true;
}
return false;
}
@Override
protected boolean checkParentPermission(String permissionCode) {
// 部门默认继承上级权限(此处简化逻辑)
return false; // 实际应根据组织架构实现
}
private void invalidateCache() {
cachedMemberCount = -1;
}
}
/**
* 员工类(Leaf)
*/
class Employee extends OrganizationComponent {
private String position; // 职位
private String[] roles; // 角色权限
public Employee(String name, String position, String[] roles) {
super(name);
this.position = position;
this.roles = roles;
}
@Override
public int countMembers() {
return 1; // 叶子节点直接返回1
}
@Override
public void printStructure(int depth) {
String indent = " ".repeat(depth);
System.out.printf("%s- %s(%s)%n",
indent, name, position);
}
@Override
protected boolean hasLocalPermission(String permissionCode) {
for (String role : roles) {
if (role.equals(permissionCode)) return true;
}
return false;
}
@Override
protected boolean checkParentPermission(String permissionCode) {
// 员工权限不继承部门权限(示例逻辑)
return false;
}
}
// ================== 客户端代码 ==================
public class CompositePatternDemo {
public static void main(String[] args) {
// 构建组织架构
OrganizationComponent root = new Department("总公司", "D001",
new String[]{"finance_approve"});
// 添加技术部
Department techDept = new Department("技术部", "D002",
new String[]{"code_review"});
techDept.add(new Employee("张三", "Java工程师",
new String[]{"dev"}));
techDept.add(new Employee("李四", "架构师",
new String[]{"dev", "design"}));
root.add(techDept);
// 添加市场部
Department marketDept = new Department("市场部", "D003",
new String[]{"campaign_manage"});
marketDept.add(new Employee("王五", "市场经理",
new String[]{"sales"}));
root.add(marketDept);
// 打印结构
System.out.println("==== 组织架构 ====");
root.printStructure(0);
// 统计人数
System.out.printf("\n总人数:%d\n", root.countMembers());
// 权限校验测试
OrganizationComponent dev = techDept.getChildren().get(0);
System.out.println("\n权限检查:");
System.out.println("张三是否有dev权限:" + dev.checkPermission("dev")); // true
System.out.println("张三是否有finance权限:" + dev.checkPermission("finance_approve")); // false
}
}
真实场景问题解决
问题类型 | 解决方案 |
---|---|
树形结构遍历效率低 | 引入缓存机制优化统计性能 |
权限管理复杂 | 模板方法统一权限校验流程,子类实现具体逻辑 |
意外修改风险 | 返回子节点列表的副本(防御性拷贝) |
叶子容器行为差异 | 父类默认抛出异常,子类按需覆盖 |
循环引用风险 | 增删操作时检查父子关系(示例未展示,实际应添加校验逻辑) |
动态扩展困难 | 通过组合模式天然支持动态结构调整 |
模式对比与选择
模式 | 适用场景 | 组合模式特点 |
---|---|---|
组合模式 | 树形结构、部分-整体关系 | 统一处理叶子与容器节点 |
装饰器模式 | 动态添加功能 | 保持接口一致性,透明扩展 |
访问者模式 | 对复杂结构进行多种操作 | 常与组合模式配合使用 |
迭代器模式 | 遍历复杂数据结构 | 为组合结构提供统一遍历接口 |
组合模式最佳实践
设计原则
单一职责原则:组件类专注结构管理,业务逻辑通过访问者模式分离
开闭原则:新增组件类型无需修改现有代码
性能优化
使用备忘录模式缓存计算结果
采用延迟加载策略初始化子节点
安全实现
使用UnsupportedOperationException约束叶子节点操作
为容器节点实现迭代器保护内部结构
扩展方向
结合观察者模式实现结构变更通知
使用原型模式快速复制子树结构
通过这个案例可以看出,组合模式在管理层次化数据和统一操作接口的场景中表现优异。实际开发中建议:
明确定义组件角色:严格区分叶子与容器节点
合理使用缓存:优化递归操作性能
防御性编程:防止客户端误用组件接口
结合其他模式:如访问者模式处理复杂业务逻辑
一句话总结
组合模式是一种结构型设计模式,它将对象组合成树形结构以表示“部分-整体”的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。
组合模式和桥接模式都是依赖抽象,但是组合模式更注重整体和局部的关联,而桥接模式更注重依赖抽象,不会去关注依赖对象之间的关联。