← 返回题目列表

使用组合模式有哪些常见误区?

高频 困难 第 11 / 25 题 更新于 2026/07/28
组合模式常见误区树结构递归过度设计

简化版

组合模式常见误区包括:没有树形结构也硬套、叶子节点暴露不该有的方法、忽略递归深度和性能、没有处理环形引用、把数据库树模型等同于组合模式、在组合节点里堆过多业务逻辑。组合模式适合部分-整体树,不适合所有包含关系。

详细版

常见误区:

  1. 普通一对多关系也强行套组合模式;
  2. 透明式接口让叶子节点暴露 add/remove 却没有合理处理;
  3. 递归遍历大树导致性能问题;
  4. 没有做环检测,异常数据导致死循环;
  5. 删除或移动节点时父子关系不一致;
  6. 把数据库 parent_id 结构直接等同于组合模式;
  7. Composite 类承担过多业务规则;
  8. 对所有节点强行使用同一个接口,导致抽象过宽;
  9. 忽略权限过滤后的树结构修剪;
  10. 没有区分构建树和使用树两个阶段。

正确使用组合模式,要先确认业务是否真的是递归树,并明确叶子和组合节点的共同能力。

完整版教学

一、误区一:没有树也硬套

组合模式适合递归树。

如果只是:

订单 -> 订单明细

这通常是一层聚合关系,不一定需要组合模式。

组合模式更适合:

节点 -> 子节点 -> 子节点 -> ...

层级不固定,结构递归,才更有价值。

二、误区二:接口设计过宽

如果 Component 接口里放太多方法:

add()
remove()
getChild()
calculate()
render()
export()

很多叶子节点可能无法合理实现。

接口应该只放真正公共的能力,子节点管理方法要根据透明式或安全式慎重设计。

三、误区三:忽略环形引用

业务上说是树,不代表数据一定干净。

错误数据可能形成环:

A -> B -> C -> A

递归遍历会无限循环。

构建树时要校验父子关系,遍历时必要情况下维护 visited 集合。

四、误区四:把数据库树模型当成组合模式

数据库里用 parent_id 存树,只是存储模型。

组合模式是内存对象设计:

Component
Leaf
Composite

两者可以配合,但不是一回事。

通常流程是:从数据库查节点列表,再组装成组合对象树。

五、误区五:组合节点变成大业务类

Composite 的主要职责是管理子节点并实现组合行为。

如果把各种业务规则都塞进去,它会变得很重。

例如菜单节点不应该承担所有权限系统逻辑,权限判断可以放到权限服务或策略中。

六、误区六:构建树和使用树混在一起

构建树时可能需要:

  • 查数据库;
  • 建索引;
  • 挂父子关系;
  • 排序;
  • 校验环。

使用树时可能只是:

  • 渲染;
  • 统计;
  • 过滤;
  • 遍历。

这两个阶段职责不同,不要全部混在 Component 里。

七、常见误区与追问

组合模式误用通常来自“看见层级就套树接口”。如果节点只有2层且叶子、容器操作完全不同,统一 Component 反而迫使叶子实现无意义的 add/remove。真正匹配的场景需要客户端对叶子和组合执行同一业务操作,并接受递归传播语义。

检查维度判定依据
适合统一叶子与容器共享核心业务操作
不宜统一两类节点行为差异远大于共性

心法:组合模式统一的是“使用方式”,不是把所有节点方法强行做成一样。

  • 误区:任何数据库 parentId 都是组合模式。 数据呈树形不等于对象协作采用统一 Component 接口。
  • 追问:如何避免叶子暴露无效方法? 选择安全式接口,或把子节点管理能力拆成单独抽象。
  • 误区:递归结构天然不会有环。 错误装配可能让祖先成为后代,必须校验或记录访问集合。
  • 追问:组合节点为何容易变成大类? 把加载、权限、统计和持久化都塞入节点会混淆结构与业务。
  • 追问:构树和遍历要分开吗? 通常应分开,构建负责数据一致性,节点只维护结构和统一操作。

八、加强记忆

组合模式别乱用:它服务于递归树,而不是所有包含关系。使用时要管好接口宽度、树构建、环检测、递归性能和职责边界,别让 Component 抽象过宽,也别让 Composite 变成大业务类。