← 返回题目列表

组合模式有哪些角色?调用流程是什么?

高频 简单 第 2 / 25 题 更新于 2026/07/28
组合模式ComponentLeafComposite调用流程

简化版

组合模式通常有三个角色:Component 定义统一组件接口,Leaf 表示叶子节点,Composite 表示组合节点并持有子组件。调用流程是客户端调用 Component 接口,如果是 Leaf 就直接执行,如果是 Composite 就递归调用它的子组件。

详细版

组合模式角色:

角色作用
Component抽象组件,定义叶子和组合对象的公共接口
Leaf叶子节点,没有子节点
Composite组合节点,可以包含多个 Component
Client通过 Component 接口统一操作对象树

调用流程:

Client 调用 root.operation()
root 如果是 Leaf:直接执行
root 如果是 Composite:遍历 children
children 中每个节点继续 operation()

组合模式的关键是 Composite 的子节点类型仍然是 Component,因此子节点可以是叶子,也可以是另一个组合节点。

完整版教学

一、Component:统一抽象

Component 定义公共能力:

interface MenuComponent {
    void print();
}

客户端只依赖这个接口。

不管传进来的是菜单项还是菜单分组,都能调用 print()

二、Leaf:叶子节点

叶子节点没有子节点。

class MenuItem implements MenuComponent {
    private final String name;

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

    public void print() {
        System.out.println(name);
    }
}

叶子节点只处理自己的行为。

三、Composite:组合节点

组合节点持有子组件:

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

    void add(MenuComponent child) {
        children.add(child);
    }

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

这里 children 的类型是 MenuComponent,所以可以添加 MenuItem,也可以添加另一个 MenuGroup

四、Client:统一调用

客户端代码:

MenuComponent root = buildMenu();
root.print();

客户端不需要判断 root 是叶子还是组合。

这就是组合模式最典型的使用方式。

五、递归调用是组合模式的自然结果

如果 MenuGroup 下面还有 MenuGroupprint() 会继续向下调用。

系统管理
  用户管理
  权限管理
    角色管理
    菜单管理

每一层都按同一个接口处理,递归结构非常自然。

六、常见误区与追问

组合模式的调用流体现递归多态。客户端持有1个 Component 引用,调用操作后,若对象是 Leaf 就直接完成;若是 Composite,则遍历3个子节点并对每个再次调用同一接口。客户端无需知道树的具体深度,但 Composite 必须维护子节点结构。

检查维度判定依据
Leaf执行基本操作并终止递归
Composite将同一操作传播给子节点

记忆钩子:Component 统一入口,Leaf 收住递归,Composite 继续递归。

  • 误区:Client 必须知道节点是叶子还是容器。 统一操作的目的正是消除客户端的类型判断。
  • 追问:Composite 能否包含另一个 Composite? 可以,这种递归包含关系构成任意深度的树。
  • 误区:Leaf 什么都不做。 它实现真正的基本业务操作,只是不管理子节点。
  • 追问:谁负责创建整棵树? 客户端、构建器或仓储都可以,组合模式主要约束使用结构。
  • 追问:怎样验证多态调用? 混合放入 Leaf 和 Composite,调用根接口并检查所有预期节点均被访问。

七、加强记忆

组合模式角色记住三个:Component 统一接口,Leaf 表示叶子,Composite 保存子节点并递归调用。客户端只面对 Component,所以能用同一套代码处理单个对象和整棵树。