← 返回题目列表

访问者模式和迭代器模式有什么区别?

高频 中等 第 1 / 25 题 更新于 2026/08/02
访问者模式迭代器模式遍历模式对比

简化版

迭代器模式关注如何顺序访问集合元素而不暴露内部结构;访问者模式关注对对象结构中的不同元素执行不同操作。迭代器解决遍历问题,访问者解决操作扩展问题,两者可以结合使用。

详细版

迭代器模式:

  • 目标是遍历集合。
  • 统一访问元素的方式。
  • 不关心元素上执行什么复杂操作。
  • 重点是 hasNext()next() 这类遍历接口。

访问者模式:

  • 目标是扩展操作。
  • 不同元素类型执行不同 visit 方法。
  • 需要元素提供 accept。
  • 重点是元素类型和访问者类型的双分派。

两者可以结合:迭代器负责遍历元素集合,访问者负责处理每个元素。

完整版教学

一、迭代器模式解决遍历封装

集合内部可能是数组、链表、树、图。客户端不应该知道它内部怎么存,只需要一个统一遍历接口。

迭代器模式把遍历状态封装起来,让客户端按统一方式访问元素。

二、访问者模式解决操作扩展

访问者模式不重点解决“怎么走到每个节点”,而是解决“走到节点后执行什么操作”。

例如 AST 可以用迭代器或递归遍历节点,但类型检查、代码生成、格式化这些操作更适合放到访问者里。

三、两者如何配合

对象结构可以用迭代器暴露遍历能力:

while (iterator.hasNext()) {
    Element element = iterator.next();
    element.accept(visitor);
}

这里迭代器负责“下一个是谁”,访问者负责“拿到之后怎么处理”。

四、常见误区与工程判断

如果一个需求只是“隐藏集合内部结构并遍历元素”,用迭代器即可。如果需求是“新增很多对不同元素的操作”,才考虑访问者。

不要因为访问者里也遍历对象结构,就认为它等于迭代器。访问者的核心不是遍历,而是把操作从元素类中分离出去。

五、遍历和操作要分开看

访问者和迭代器经常一起出现,但它们不是同一层问题。迭代器解决的是“如何按统一方式访问集合元素”,重点是遍历过程;访问者解决的是“对遍历到的不同元素执行什么操作”,重点是行为扩展。

在工程里,ObjectStructure 内部可能用迭代器遍历元素,然后对每个元素调用 accept(visitor)。这说明迭代器可以成为访问者流程中的一部分,但不能替代访问者。迭代器不知道元素类型对应哪些业务处理,也不负责把新增操作封装起来。

面试时可以这样区分:如果问题是屏蔽集合内部结构、统一遍历方式,考虑迭代器;如果问题是稳定元素集合上不断增加处理逻辑,考虑访问者。一个管“走到谁”,一个管“对谁做什么”。

如果面试官继续追问“访问者里是不是也要遍历”,可以承认很多实现确实会遍历,但遍历只是把元素交给访问者的过程,不是模式的核心收益。真正的收益在于同一批元素上可以挂不同访问者,分别完成统计、导出、校验等操作。

六、用工程约束检验答案

迭代器回答“下一个元素怎么拿”,访问者回答“拿到不同类型元素后做什么”。处理 1000 个树节点时,迭代器可以隐藏深度优先遍历,访问者则对文件、目录等具体节点执行统计;两者处在不同职责层。

检查项核心判断工程含义
迭代器封装遍历顺序和游标通常不关心具体业务操作
访问者封装针对元素类型的操作通常不负责选择下一个元素
组合使用Iterator 提供元素每个元素 accept 同一 Visitor

把关键关系压缩成一条可复述的路径:

Iterator.hasNext / next
             -> Element
             -> accept(Visitor)
             -> 类型化业务处理

能一起使用的两个模式通常不是替代关系;回答时要分别指出遍历维度与操作维度。

落地前可以再按下面 3 步复核:

  1. 先说明“迭代器”的核心机制:封装遍历顺序和游标;再交代边界:通常不关心具体业务操作。
  2. 接着分析“访问者”:封装针对元素类型的操作;不能遗漏对应代价或结果:通常不负责选择下一个元素。
  3. 最后用“组合使用”检查方案:Iterator 提供元素;验收时确认每个元素 accept 同一 Visitor。

这三项构成完整判断链:先讲清迭代器,再说明访问者,最后用组合使用检验实现是否越界。

面试中若能给出违反“每个元素 accept 同一 Visitor”的反例,再说明修正办法,答案就从模式定义落到了可验证的工程决策。

七、常见误区与追问

  • 误区:只看到“迭代器”就认为方案成立。 必须同时说明核心机制“封装遍历顺序和游标”和工程边界“通常不关心具体业务操作”。
  • 误区:把“访问者”当成无条件结论。 只有在“封装针对元素类型的操作”成立时,才能据此讨论“通常不负责选择下一个元素”。
  • 追问:访问者能否自己遍历? 可以,但会混合遍历与操作职责,除非结构本身要求访问者控制递归。
  • 追问:迭代器知道元素具体类型吗? 通常只暴露统一 Element 类型,具体操作仍可交给多态或访问者。
  • 追问:Composite 中谁遍历子节点? 可以由组合节点、独立迭代器或访问者控制,需统一约定。
  • 追问:只需打印集合该用谁? 普通循环通常足够,不必为了模式而模式。
  • 追问:二者共享的目标是什么? 都降低客户端对对象结构细节的直接依赖,但解决的细节不同。

八、加强记忆

记忆时抓住这条主线:迭代器管遍历;访问者管操作扩展;两者可以配合使用;是否需要 accept 是区分访问者的重要信号。面试回答先给出模式意图,再用调用链或数据流说明角色协作,最后主动交代适用边界与工程代价。