首页/开发/代码质量与评审速查/迭代器模式 Iterator(行为型)
设计原则与模式62 条

迭代器模式 Iterator(行为型)

提供顺序访问聚合元素的统一方式而不暴露内部结构:语言内建(for-each、生成器)已成默认形态;自定义迭代器要处理并发修改与失效语义。

迭代器模式解决什么

迭代器模式提供按顺序访问聚合元素的统一方式,同时不暴露内部结构。今天的语言大多已经内置这一能力:遍历语法、生成器、流式接口都是它的现成形态,因此自定义实现主要用于树形结构、跨数据源组合与惰性计算这类内建遍历覆盖不到的场景。使用时要明确两个约定:遍历过程中容器被修改时如何表现,以及迭代器失效后的行为。

基本信息

意图统一遍历协议,封装内部数据结构
常见形态下一个元素判断取值的方法对,或语言生成器
适用树形结构、多数据源合并、惰性序列
风险遍历过程中容器被修改导致行为未定义

典型使用场景

  • 树形结构深度优先遍历:用生成器递归产出节点,调用方不必关心递归细节
  • 多数据源合并读取:把分页接口包装成统一迭代,调用方按顺序取用
  • 惰性序列处理:元素按需计算,避免一次性构造大集合
  • 自定义容器类型:为内部结构提供标准遍历能力,便于配合通用算法
  • 测试替身:为假数据源提供与真实数据源一致的遍历接口

生成器形态

生成器形态
# 树形结构深度优先遍历:调用方只面对统一的顺序
def walk(node):
    yield node.value
    for child in node.children:
        yield from walk(child)

# 使用:不需要暴露 children 结构
for value in walk(root):
    print(value)

实现要点

要点正确做法常见问题
失效语义明确列出修改容器时的行为遍历中修改导致结果错乱或抛出不一致的异常
游标位置游标封装在迭代器内部暴露游标字段,调用方可任意跳转,封装目标落空
一次性明确迭代器能否重复遍历多次遍历得到空结果,调用方困惑
惰性求值异常在取元素时抛出,需说明时机调用方以为构造成功,取用时才失败
资源释放遍历结束或中断时释放资源提前退出导致连接或文件句柄未释放
语言已内置遍历协议时,优先实现该协议而不是自造方法对:这样对象可以直接用于标准循环、流式操作与通用工具函数,不必为每种用法额外适配。
遍历过程中修改容器是最常见的缺陷来源:不同实现对同类操作的表现可能不一致,有的立即失败,有的静默跳过元素。若业务确实需要边遍历边修改,应先收集待处理元素再统一修改。

落地检查清单

  • 遍历过程中修改容器的行为有明确定义并写进文档
  • 迭代器可重复使用与否有说明
  • 提前中断遍历时资源能正确释放
  • 自定义迭代器有对应测试,覆盖空集合与单元素情形

易错点

  • 迭代器暴露内部游标:调用方可任意调整位置,封装目标落空,行为难以预测
  • 并发修改行为未定义:有的实现静默跳过元素,有的直接报错,同一份代码在不同路径下表现不一致
  • 忘记释放资源:遍历中途返回导致连接或文件句柄泄漏,长时间运行后耗尽句柄
  • 自定义迭代器缺少空集合测试:零元素场景下出现异常或死循环,只有特定数据才会触发

数据来源与参考

  • 《设计模式》(GoF)· Iterator
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌