组合模式详解

发布于:2025-03-23 ⋅ 阅读:(75) ⋅ 点赞:(0)

以下是一个结合组合模式解决实际开发问题的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约束叶子节点操作
为容器节点实现迭代器保护内部结构

扩展方向

结合观察者模式实现结构变更通知
使用原型模式快速复制子树结构
通过这个案例可以看出,组合模式在管理层次化数据和统一操作接口的场景中表现优异。实际开发中建议:
明确定义组件角色:严格区分叶子与容器节点
合理使用缓存:优化递归操作性能
防御性编程:防止客户端误用组件接口
结合其他模式:如访问者模式处理复杂业务逻辑

一句话总结

组合模式是一种结构型设计模式,它将对象组合成树形结构以表示“部分-整体”的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。

组合模式和桥接模式都是依赖抽象,但是组合模式更注重整体和局部的关联,而桥接模式更注重依赖抽象,不会去关注依赖对象之间的关联。


网站公告

今日签到

点亮在社区的每一天
去签到