9.设计模式-COMPOSITE(组合)

一、模式定义与核心价值

组合模式是一种结构型设计模式,其核心目标是表示对象的部分-整体层次结构,使得客户端可以统一处理单个对象和组合对象。该模式通过树形结构组织对象,解决以下核心问题:

  1. 统一接口:消除叶子节点(简单对象)与容器节点(复合对象)的差异,使客户端无需区分操作类型
  2. 递归处理:支持对树形结构的深度遍历与批量操作(如渲染、删除、权限校验)
  3. 动态扩展:允许运行时动态添加/删除节点,构建复杂层次结构

工业级价值

  • 文件系统管理(文件与文件夹的统一操作)
  • UI组件库开发(嵌套组件的统一渲染)
  • 组织架构建模(部门与员工的层级关系)

二、模式组成与UML类图

核心角色

  1. Component(抽象构件)
    • 定义所有对象的统一接口(如display()方法)
    • 声明管理子节点的方法(add()/remove()),默认实现可抛出异常
  1. Leaf(叶子构件)
    • 表示树形结构的末端节点(如单个文件、按钮)
    • 不包含子节点,实现基础业务逻辑
  1. Composite(容器构件)
    • 存储子构件集合(List/Map结构)
    • 实现递归操作逻辑(如遍历渲染子节点)

UML类图

classDiagram
    class Component {
        <<interface>>
        +operation()
        +add(Component)
        +remove(Component)
        +getChild(int)
    }

    class Leaf {
        +operation()
    }

    class Composite {
        -children: List<Component>
        +operation()
        +add(Component)
        +remove(Component)
        +getChild(int)
    }

    Component <|-- Leaf
    Component <|-- Composite
    Composite o-- Component


三、代码实现示例

场景:实现文件系统管理(文件与文件夹的统一操作)

1. 抽象构件(Component)
public abstract class FileSystemComponent {
    protected String name;

    public FileSystemComponent(String name) {
        this.name = name;
    }

    // 基础操作
    public abstract void display(int indent);

    // 容器方法(默认不支持)
    public void add(FileSystemComponent component) {
        throw new UnsupportedOperationException();
    }

    public void remove(FileSystemComponent component) {
        throw new UnsupportedOperationException();
    }
}
2. 叶子构件(Leaf)
public class File extends FileSystemComponent {
    public File(String name) {
        super(name);
    }

    @Override
    public void display(int indent) {
        System.out.println(" ".repeat(indent) + "📄 " + name);
    }
}
3. 容器构件(Composite)
public class Directory extends FileSystemComponent {
    private List<FileSystemComponent> children = new ArrayList<>();

    public Directory(String name) {
        super(name);
    }

    @Override
    public void display(int indent) {
        System.out.println(" ".repeat(indent) + "📁 " + name);
        children.forEach(child -> child.display(indent + 2));
    }

    @Override
    public void add(FileSystemComponent component) {
        children.add(component);
    }

    @Override
    public void remove(FileSystemComponent component) {
        children.remove(component);
    }
}
4. 客户端调用
public class Client {
    public static void main(String[] args) {
        Directory root = new Directory("Project");

        Directory src = new Directory("src");
        src.add(new File("Main.java"));
        src.add(new File("Utils.java"));

        Directory test = new Directory("test");
        test.add(new File("MainTest.java"));

        root.add(src);
        root.add(test);
        root.display(0);
    }
}

/* 输出:
📁 Project
  📁 src
    📄 Main.java
    📄 Utils.java
  📁 test
    📄 MainTest.java
*/

四、工业级源码应用

  1. Java集合框架
    • java.util.Collections.unmodifiableList():返回的不可变列表本质是组合模式实现,统一处理单个元素与子列表
  1. Android UI系统
    • ViewGroupViewViewGroup作为容器构件管理子视图,Button/TextView作为叶子构件,通过onDraw()统一渲染
  1. Spring框架
    • CompositeCacheManager:组合多个缓存管理器(如Redis+Ehcache),提供统一的缓存操作接口
  1. 游戏开发引擎
    • Unity的GameObject:支持嵌套父子对象,通过Transform组件实现层级变换的统一管理
  1. 前端框架
    • React的虚拟DOM树:组件树通过组合模式构建,ReactElement作为抽象构件,DOM节点自定义组件分别实现叶子/容器逻辑3****6

五、模式优劣与选型建议

优势

  • 简化客户端逻辑:屏蔽对象类型差异,统一操作接口
  • 支持递归处理:天然适合树形结构遍历(如权限校验、数据统计)
  • 高扩展性:新增节点类型无需修改现有代码(开闭原则)

劣势

  • 接口污染风险:容器方法可能对叶子节点无意义(需权衡透明性与安全性)
  • 性能损耗:深层次递归遍历可能影响效率(需结合缓存优化)

最佳实践

  1. 优先透明性:在安全要求不高的场景,保持接口统一性
  2. 限制树深度:避免超深嵌套导致栈溢出(可改用迭代遍历)
  3. 结合访问者模式:解耦树操作与业务逻辑,提升可维护性

总结

组合模式通过树形结构组织统一接口抽象,为复杂层次系统提供了优雅的解决方案。在Java生态中,该模式已深度融入集合框架、Spring等核心组件,并在前端、游戏引擎等领域展现强大生命力。掌握组合模式的关键在于准确识别树形结构需求,并在透明性与安全性之间找到平衡点,从而构建出灵活可扩展的层级管理系统。

posted @ 2025-04-12 10:43  雾里看花的少年  阅读(91)  评论(0)    收藏  举报