迭代器模式:定义、结构、实现、优缺点、应用场景
迭代器模式,说白了就是提供一种统一的方式来遍历集合对象。你想想看,我们平时写代码,经常要遍历数组、列表、树、图这些数据结构。如果没有迭代器,每个集合都得自己暴露内部结构,那代码就乱套了。
我个人习惯把迭代器模式叫做"遍历的标准化接口"。它把遍历逻辑从集合中抽离出来,让客户端代码不用关心底层是数组还是链表,只管调用 next() 和 hasNext() 就行。
模式定义
迭代器模式(Iterator Pattern)属于行为型设计模式。它提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。
嗯,这里要注意:核心思想就两点——分离遍历行为和隐藏内部结构。
模式结构
迭代器模式的结构其实很清晰,我画个图你就明白了:
结构中的角色就四个:
- Iterator(迭代器接口):定义 hasNext()、next() 等基本操作
- ConcreteIterator(具体迭代器):实现遍历逻辑,维护当前游标位置
- Aggregate(聚合接口):定义创建迭代器的方法
- ConcreteAggregate(具体聚合):实现聚合接口,返回对应的迭代器实例
代码实现
我拿一个实际项目中的例子来说。之前我在做一个报表系统,需要遍历不同格式的数据源——有的来自数据库,有的来自内存缓存。用迭代器模式就特别合适。
// 迭代器接口
public interface Iterator<T> {
boolean hasNext();
T next();
void remove();
}
// 具体迭代器 - 数组迭代器
public class ArrayIterator<T> implements Iterator<T> {
private T[] items;
private int cursor = 0;
public ArrayIterator(T[] items) {
this.items = items;
}
@Override
public boolean hasNext() {
return cursor < items.length;
}
@Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return items[cursor++];
}
@Override
public void remove() {
throw new UnsupportedOperationException("数组不支持删除");
}
}
// 聚合接口
public interface Aggregate<T> {
Iterator<T> createIterator();
}
// 具体聚合 - 数据集合
public class DataCollection<T> implements Aggregate<T> {
private T[] items;
public DataCollection(T[] items) {
this.items = items;
}
@Override
public Iterator<T> createIterator() {
return new ArrayIterator<>(items);
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
String[] data = {"A", "B", "C", "D"};
DataCollection<String> collection = new DataCollection<>(data);
Iterator<String> iterator = collection.createIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
💡 我的小技巧:实际项目中,我习惯让迭代器支持"快速失败"(fail-fast)。就是在遍历过程中,如果集合被修改了,迭代器能立刻抛出异常。Java 的 ArrayList 就是这么干的。
优缺点分析
| 优点 | 缺点 |
|---|---|
|
|
⚠️ 避坑指南:我曾经在一个项目中,为了"优雅"给所有集合都套上了迭代器模式。结果发现有些集合就几个元素,用 for 循环三行搞定,硬生生写了两个类。后来我学乖了——迭代器模式适合复杂遍历或多种遍历方式,别为了用模式而用模式。
应用场景
什么时候该用迭代器模式?我总结了几个典型场景:
- 需要多种遍历方式:比如既要正序遍历又要逆序遍历,还要按条件过滤
- 想隐藏集合内部结构:客户端不想知道底层是数组、链表还是树
- 需要统一遍历接口:不同数据源用同一套代码遍历
- 需要同时遍历多个集合:比如做数据对比、合并操作
举个实际例子。我之前做的一个日志分析系统,日志来源有文件、数据库、消息队列三种。每种来源的数据结构完全不同,但分析逻辑是一样的。我让它们都实现 Aggregate 接口,返回统一的迭代器。分析模块只需要写一套遍历代码,省了至少 40% 的重复工作。
📌 核心要点回顾:
- 迭代器模式把遍历行为从集合中抽离出来
- 核心接口就两个:hasNext() 和 next()
- 适合复杂遍历场景,简单场景别硬用
- Java、C#、Python 等语言已经内置了迭代器支持
其实现在很多语言都内置了迭代器。比如 Java 的 Iterable 接口、Python 的 __iter__ 和 __next__、C# 的 IEnumerable。但理解它的设计思想更重要——分离关注点,让遍历变得可扩展、可复用。这就是迭代器模式的价值所在。
公众号:蓝海资料掘金营,微信deep3321