迭代器模式和组合模式、访问者模式有什么区别?
简化版
迭代器模式关注如何遍历对象集合;组合模式关注如何把对象组织成树形整体;访问者模式关注在不改数据结构的情况下新增操作。它们常一起出现,但解决的问题不同。
详细版
三者的核心区别是:
- 组合模式:解决对象结构问题,把叶子和容器统一成树。
- 迭代器模式:解决遍历访问问题,隐藏集合或树的内部遍历细节。
- 访问者模式:解决操作扩展问题,把作用在节点上的操作从节点类中分离出来。
例如文件系统:
- 组合模式表示文件夹和文件的树形结构。
- 迭代器模式遍历所有文件节点。
- 访问者模式统计大小、生成索引、扫描病毒等操作。
完整版教学
一、迭代器模式关注遍历
迭代器模式的核心问题是:如何逐个访问元素,同时不暴露内部结构。
它关心:
- 从哪里开始。
- 是否还有下一个。
- 下一个是谁。
- 遍历顺序如何封装。
它不负责定义树形结构,也不负责新增业务操作。
二、组合模式关注结构
组合模式的核心问题是:如何让单个对象和组合对象具有一致接口。
例如文件和文件夹:
- 文件是叶子节点。
- 文件夹是容器节点。
- 客户端可以统一调用
display()或size()。
组合模式负责把对象组织成整体和部分的层次结构。
三、访问者模式关注操作扩展
访问者模式的核心问题是:数据结构稳定,但操作经常增加。
例如语法树节点类型比较稳定,但要新增:
- 类型检查。
- 代码生成。
- 格式化。
- 复杂度分析。
访问者可以把这些操作放到独立类中,而不是不断修改节点类。
四、三者如何配合
在树形结构中,它们经常配合使用。
例如菜单系统:
- 用组合模式组织菜单和菜单项。
- 用迭代器模式遍历整棵菜单树。
- 用访问者模式对每个节点执行权限检查、导出、统计等操作。
这样结构、遍历、操作各自独立。
五、为什么容易混淆
它们都经常出现在集合或树结构里,所以容易混在一起。
判断时要看主要矛盾:
- 如果问题是“整体和部分如何统一”,优先看组合模式。
- 如果问题是“如何隐藏遍历细节”,优先看迭代器模式。
- 如果问题是“如何在不改节点类的情况下增加操作”,优先看访问者模式。
六、面试回答建议
可以这样答:
迭代器模式解决遍历,组合模式解决树形结构,访问者模式解决操作扩展。它们可以配合使用,比如文件系统用组合模式建树,用迭代器遍历节点,用访问者统计大小或生成报表。
这个回答既区分了目的,也给了实际组合场景。
七、常见误区与追问
三种模式经常一起出现在树结构中,却关注不同问题。组合模式组织 N 个节点的部分—整体关系;迭代器决定按什么顺序访问;访问者把对节点类型的操作集中起来。比如文件树用 Composite 建模、Iterator 做深度优先、Visitor 计算权限报告。
| 检查维度 | 判定依据 |
|---|---|
| 组合 / 迭代器 | 组织树 / 封装遍历游标 |
| 访问者 | 在稳定节点结构上扩展操作 |
Composite(结构) -> Iterator(顺序) -> Visitor(操作)
记忆钩子:组合回答“长什么样”,迭代器回答“怎么走”,访问者回答“走到后做什么”。
- 误区:使用组合模式后不需要迭代器。 组合提供递归结构,但客户端仍可能需要独立遍历策略。
- 追问:访问者为什么不等于迭代器回调? 访问者利用双分派按具体节点类型执行不同操作。
- 误区:迭代器负责修改节点业务。 它主要控制访问顺序,业务操作应由客户端或访问者完成。
- 追问:三者能否组合? 可以,而且树形对象处理中非常常见。
- 追问:节点类型频繁变化时 Visitor 合适吗? 不太合适,每新增节点类型都要修改访问者接口和实现。
八、加强记忆
这三个模式可以记成“结构、走法、操作”:组合模式管结构,迭代器模式管走法,访问者模式管对节点做什么。看清问题落在哪一层,就不容易混淆。