迭代器模式:统一数据遍历方式的设计模式
一、模式核心:将数据遍历逻辑与数据结构解耦
在软件开发中,不同的数据结构(如数组、链表、集合)有不同的遍历方式。如果客户端直接依赖这些数据结构的内部实现来遍历元素,会导致代码耦合度高且难以维护。
迭代器模式(Iterator Pattern) 提供了一种统一的方式来遍历不同的数据结构,而无需暴露数据结构的内部表示。其核心解决:
- 解耦遍历逻辑:将遍历逻辑从数据结构中分离,客户端通过迭代器统一操作。
- 支持多种遍历方式:可以为同一数据结构提供不同的遍历策略(如正向遍历、反向遍历)。
- 简化客户端代码:客户端无需关心数据结构的具体类型,只需通过迭代器接口遍历元素。
核心思想与 UML 类图
迭代器模式包含以下角色:
- 抽象迭代器(Iterator) :定义遍历元素的接口(如
hasNext()
、next()
)。 - 具体迭代器(Concrete Iterator):实现抽象迭代器接口,负责具体的数据遍历。
- 抽象聚合(Aggregate) :定义创建迭代器的接口(如
createIterator()
)。 - 具体聚合(Concrete Aggregate):实现抽象聚合接口,返回具体迭代器。

二、核心实现:数组集合的迭代器
1. 定义抽象迭代器接口
java
public interface Iterator {
boolean hasNext(); // 是否有下一个元素
Object next(); // 获取下一个元素
}
2. 定义抽象聚合接口
java
public interface Aggregate {
Iterator createIterator(); // 创建迭代器
}
3. 实现具体聚合类(数组集合)
java
public class ConcreteAggregate implements Aggregate {
private Object[] items;
private int size;
public ConcreteAggregate(int capacity) {
items = new Object[capacity];
size = 0;
}
public void add(Object item) {
if (size < items.length) {
items[size++] = item;
}
}
@Override
public Iterator createIterator() {
return new ConcreteIterator(this); // 返回具体迭代器
}
// 获取集合长度(供迭代器使用)
public int getSize() {
return size;
}
// 获取指定索引的元素(供迭代器使用)
public Object getItem(int index) {
return items[index];
}
}
4. 实现具体迭代器类
java
public class ConcreteIterator implements Iterator {
private ConcreteAggregate aggregate;
private int index; // 当前遍历位置
public ConcreteIterator(ConcreteAggregate aggregate) {
this.aggregate = aggregate;
index = 0;
}
@Override
public boolean hasNext() {
return index < aggregate.getSize(); // 未遍历到末尾
}
@Override
public Object next() {
if (hasNext()) {
return aggregate.getItem(index++); // 返回当前元素并后移索引
}
return null;
}
}
5. 客户端使用迭代器
java
public class ClientDemo {
public static void main(String[] args) {
// 创建聚合对象并添加元素
ConcreteAggregate aggregate = new ConcreteAggregate(3);
aggregate.add("Apple");
aggregate.add("Banana");
aggregate.add("Cherry");
// 获取迭代器并遍历元素
Iterator iterator = aggregate.createIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
输出结果:
plaintext
Apple
Banana
Cherry
三、进阶:支持反向遍历的迭代器
通过扩展具体迭代器,可以为同一聚合提供不同的遍历策略(如反向遍历)。
1. 新增反向迭代器类
java
public class ReverseIterator implements Iterator {
private ConcreteAggregate aggregate;
private int index; // 当前遍历位置(从末尾开始)
public ReverseIterator(ConcreteAggregate aggregate) {
this.aggregate = aggregate;
index = aggregate.getSize() - 1; // 初始位置为最后一个元素
}
@Override
public boolean hasNext() {
return index >= 0; // 未遍历到开头
}
@Override
public Object next() {
if (hasNext()) {
return aggregate.getItem(index--); // 返回当前元素并前移索引
}
return null;
}
}
2. 修改聚合类以支持多种迭代器
java
public class ConcreteAggregate {
// ... 原有代码 ...
// 新增创建反向迭代器的方法
public Iterator createReverseIterator() {
return new ReverseIterator(this);
}
}
3. 客户端使用反向迭代器
java
public class ClientDemo {
public static void main(String[] args) {
// ... 创建聚合对象 ...
// 反向遍历
Iterator reverseIterator = aggregate.createReverseIterator();
while (reverseIterator.hasNext()) {
System.out.println(reverseIterator.next());
}
}
}
输出结果:
plaintext
Cherry
Banana
Apple
四、框架与源码中的迭代器实践
1. Java 集合框架(Iterator
接口)
Java 的 java.util.Iterator
是迭代器模式的标准实现,所有集合类(如 ArrayList
、HashSet
)均实现了 Iterable
接口(包含 iterator()
方法)。
java
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
2. MyBatis 结果集遍历
MyBatis 在处理查询结果时,通过 ResultHandler
接口实现类似迭代器的功能,将结果集逐行处理,避免一次性加载大量数据到内存。
java
sqlSession.select("selectUserList", new ResultHandler<User>() {
@Override
public void handleResult(ResultContext<User> context) {
User user = context.getResultObject();
processUser(user); // 逐行处理结果
}
});
五、避坑指南:正确使用迭代器模式的 3 个要点
1. 确保迭代器的独立性
每个迭代器应独立维护遍历状态,避免多个迭代器共享状态导致数据不一致。
2. 处理并发修改异常
在迭代过程中修改聚合对象(如新增 / 删除元素)可能导致 ConcurrentModificationException
,需通过 fail-fast
机制或复制集合数据处理。
3. 避免过度设计
对于简单的数据结构(如数组),直接使用索引遍历可能更高效,无需强行引入迭代器模式。
六、总结:何时该用迭代器模式?
适用场景 | 核心特征 | 典型案例 |
---|---|---|
数据结构复杂 | 数据结构内部实现复杂,需隐藏遍历细节 | 链表、树状结构遍历 |
多遍历策略 | 需要为同一数据结构提供多种遍历方式 | 正向 / 反向遍历、深度 / 广度优先 |
解耦客户端与数据结构 | 客户端不依赖数据结构的具体实现 | 集合框架、ORM 结果集处理 |
迭代器模式通过分离数据遍历逻辑,提升了代码的可维护性和扩展性。下一篇我们将探讨观察者模式,解析如何实现对象间的消息订阅与发布,敬请期待!
扩展思考:迭代器模式 vs 枚举(Enumeration)
类型 | 功能差异 | 线程安全 | 遍历控制 |
---|---|---|---|
迭代器 | 支持元素删除(remove() ) |
非线程安全 | 主动控制遍历 |
枚举(旧版) | 仅支持遍历,不支持删除 | 非线程安全 | 被动遍历 |
在 Java 中,迭代器已全面替代枚举,成为集合遍历的标准方式。