Skip to content
Method约 1 分钟0 个小节更新于 2026/06/19在线编辑

组合模式

组合模式用于处理树形结构,让客户端可以用统一方式操作“单个对象”和“对象集合”。

一句话理解:把对象组织成树,叶子节点和组合节点使用同一个接口。

解决什么问题

很多业务天然是树形结构:

  • 部门和员工。
  • 菜单和子菜单。
  • 文件夹和文件。
  • 分类和商品分类。
  • 权限节点和子权限。

如果客户端要区分叶子节点和父节点,代码会充满判断:

java
if (node is folder) {
    for child...
} else {
    handle file
}

组合模式把共同操作抽象成统一接口,让客户端递归处理即可。

基本结构

text
Component
  ^
  |
Leaf
Composite -> List<Component>

角色:

  • Component:统一接口。
  • Leaf:叶子节点,没有子节点。
  • Composite:组合节点,包含多个子节点。

Java 示例

菜单节点接口:

java
interface MenuComponent {
    String name();

    void print(String prefix);
}

叶子菜单:

java
class MenuItem implements MenuComponent {
    private final String name;

    MenuItem(String name) {
        this.name = name;
    }

    public String name() {
        return name;
    }

    public void print(String prefix) {
        System.out.println(prefix + "- " + name);
    }
}

菜单分组:

java
import java.util.ArrayList;
import java.util.List;

class MenuGroup implements MenuComponent {
    private final String name;
    private final List<MenuComponent> children = new ArrayList<>();

    MenuGroup(String name) {
        this.name = name;
    }

    public MenuGroup add(MenuComponent child) {
        children.add(child);
        return this;
    }

    public String name() {
        return name;
    }

    public void print(String prefix) {
        System.out.println(prefix + "+ " + name);
        for (MenuComponent child : children) {
            child.print(prefix + "  ");
        }
    }
}

使用:

java
MenuGroup root = new MenuGroup("系统管理")
        .add(new MenuItem("用户管理"))
        .add(new MenuItem("角色管理"))
        .add(new MenuGroup("权限管理")
                .add(new MenuItem("菜单权限"))
                .add(new MenuItem("接口权限")));

root.print("");

使用场景

  • 树形菜单。
  • 文件目录。
  • 组织架构。
  • 分类树。
  • 权限树。
  • 表达式树。

优点

  • 客户端统一处理叶子和组合对象。
  • 递归遍历结构清晰。
  • 新增节点类型比较方便。
  • 适合表达部分和整体关系。

缺点

  • 过度统一可能让接口包含叶子节点不需要的方法。
  • 树太深时要注意递归深度和性能。
  • 如果节点差异很大,强行统一会让模型别扭。

透明式和安全式

透明式组合把 add/remove 放在公共接口中,客户端简单,但叶子节点也会暴露不适合的方法。

安全式组合只在组合节点中提供 add/remove,模型更严谨,客户端可能需要知道节点类型。

实际开发中更常用安全式组合。

实战注意

组合模式的核心不是“用了递归”,而是让客户端以统一接口处理树中的所有节点。

以工程实践沉淀知识,以文档复盘成长。