如何运用迭代器模式简化对复杂数据源的访问过程?
- 内容介绍
- 相关推荐
本文共计916个文字,预计阅读时间需要4分钟。
代器模式的核心作用,是将如何存和如何取分离。面对树、图、嵌套对象、自定义容器这类复杂数据源,你不必让业务代码直接递归遍历或手动维护指针,而应提供一个统一、稳定、可替换的访问入口——这就是迭代器。
明确分离职责:集合只管存储,迭代器专责遍历
集合类(Aggregate)不再承担遍历逻辑,只负责创建对应的迭代器实例。比如一个 CategoryTree 类,内部是多层子节点嵌套,它只需实现一个 getIterator() 方法,返回一个实现了标准接口的树迭代器对象。这样,即使将来把树结构换成图或扁平化缓存,只要迭代器接口不变,所有遍历调用都不用改。
- 集合类不暴露节点引用、父子关系、遍历状态等内部字段
- 迭代器持有对集合的弱引用或只读快照,避免外部干扰遍历过程
- 客户端只依赖
hasNext()和next()这类通用方法,不感知底层是 DFS 还是 BFS
为不同遍历策略提供独立迭代器实现
同一份数据,可能需要深度优先、广度优先、层级顺序、过滤后顺序等多种访问方式。把这些逻辑硬塞进集合类会污染其单一职责。正确做法是为每种策略写一个具体迭代器:
-
DepthFirstTreeIterator:用栈模拟递归,按子树深入到底再回溯 -
BreadthFirstTreeIterator:用队列逐层展开,适合查找最近节点 -
FilteredTreeIterator:包装另一个迭代器,跳过不满足条件的节点 - 所有迭代器都实现同一接口(如
Iterator<T>),客户端可无缝切换
利用语言原生协议提升兼容性与简洁性
在 JavaScript 中,直接实现 [Symbol.iterator]() 方法,就能让自定义集合支持 for...of、扩展运算符、解构等语法;在 C# 中实现 IEnumerable 和 IEnumerator,即可接入 foreach 生态。这不只是语法糖,而是让复杂数据源自然融入语言遍历体系的关键一步。
- 实现
Symbol.iterator返回一个生成器函数,天然支持惰性求值和异步迭代(配合Symbol.asyncIterator) - 避免手写 while 循环 + hasNext 判断,降低出错概率
- 第三方库(如 Lodash、RxJS)也能识别并复用你的迭代器协议
注意状态隔离与线程/协程安全
多个地方同时遍历同一个复杂数据源时,必须保证彼此互不干扰。每个迭代器实例应完全独立维护自己的位置、路径栈、已访问标记等状态。
- 不要在集合上共享游标变量(如
currentIndex) - 对不可变数据源,迭代器可复用快照;对可变数据源,建议在构造时做浅拷贝或冻结关键结构
- 异步迭代器需确保
next()返回 Promise,并处理并发调用的排队逻辑
本文共计916个文字,预计阅读时间需要4分钟。
代器模式的核心作用,是将如何存和如何取分离。面对树、图、嵌套对象、自定义容器这类复杂数据源,你不必让业务代码直接递归遍历或手动维护指针,而应提供一个统一、稳定、可替换的访问入口——这就是迭代器。
明确分离职责:集合只管存储,迭代器专责遍历
集合类(Aggregate)不再承担遍历逻辑,只负责创建对应的迭代器实例。比如一个 CategoryTree 类,内部是多层子节点嵌套,它只需实现一个 getIterator() 方法,返回一个实现了标准接口的树迭代器对象。这样,即使将来把树结构换成图或扁平化缓存,只要迭代器接口不变,所有遍历调用都不用改。
- 集合类不暴露节点引用、父子关系、遍历状态等内部字段
- 迭代器持有对集合的弱引用或只读快照,避免外部干扰遍历过程
- 客户端只依赖
hasNext()和next()这类通用方法,不感知底层是 DFS 还是 BFS
为不同遍历策略提供独立迭代器实现
同一份数据,可能需要深度优先、广度优先、层级顺序、过滤后顺序等多种访问方式。把这些逻辑硬塞进集合类会污染其单一职责。正确做法是为每种策略写一个具体迭代器:
-
DepthFirstTreeIterator:用栈模拟递归,按子树深入到底再回溯 -
BreadthFirstTreeIterator:用队列逐层展开,适合查找最近节点 -
FilteredTreeIterator:包装另一个迭代器,跳过不满足条件的节点 - 所有迭代器都实现同一接口(如
Iterator<T>),客户端可无缝切换
利用语言原生协议提升兼容性与简洁性
在 JavaScript 中,直接实现 [Symbol.iterator]() 方法,就能让自定义集合支持 for...of、扩展运算符、解构等语法;在 C# 中实现 IEnumerable 和 IEnumerator,即可接入 foreach 生态。这不只是语法糖,而是让复杂数据源自然融入语言遍历体系的关键一步。
- 实现
Symbol.iterator返回一个生成器函数,天然支持惰性求值和异步迭代(配合Symbol.asyncIterator) - 避免手写 while 循环 + hasNext 判断,降低出错概率
- 第三方库(如 Lodash、RxJS)也能识别并复用你的迭代器协议
注意状态隔离与线程/协程安全
多个地方同时遍历同一个复杂数据源时,必须保证彼此互不干扰。每个迭代器实例应完全独立维护自己的位置、路径栈、已访问标记等状态。
- 不要在集合上共享游标变量(如
currentIndex) - 对不可变数据源,迭代器可复用快照;对可变数据源,建议在构造时做浅拷贝或冻结关键结构
- 异步迭代器需确保
next()返回 Promise,并处理并发调用的排队逻辑

