设计模式(十七)行为型:迭代器模式详解
迭代器模式(Iterator Pattern)是 GoF 23 种设计模式中的行为型模式之一,其核心价值在于提供一种统一的方式遍历聚合对象(如集合、容器)中的元素,而无需暴露其内部表示结构。它将遍历算法从聚合对象中分离出来,封装在独立的迭代器对象中,实现了“单一职责原则”和“开闭原则”。迭代器模式是现代编程语言集合框架的基石,广泛应用于各种数据结构(列表、树、图、哈希表)的遍历操作,是实现
for-each
循环、流式处理(Stream)、延迟计算、外部迭代等机制的核心支撑,是构建可复用、可扩展、高内聚低耦合系统的必备设计模式。
一、详细介绍
迭代器模式解决的是“客户端需要访问聚合对象中的所有元素,但又不希望依赖其内部实现细节”的问题。在传统设计中,聚合类(如 List
、Tree
)通常提供 get(i)
或 elements()
等方法让客户端直接访问内部数据,这导致:
- 客户端代码与聚合的内部结构(数组、链表、树)紧耦合;
- 聚合类职责过重,既管理数据又提供遍历逻辑;
- 难以支持多种遍历方式(如正序、逆序、深度优先、广度优先);
- 并发修改时难以保证遍历的安全性。
迭代器模式通过引入一个独立的迭代器对象(Iterator) 来封装遍历过程。客户端通过迭代器提供的统一接口(如 hasNext()
、next()
)访问元素,而无需关心底层是数组、链表还是树。聚合对象(Aggregate)负责创建并返回一个合适的迭代器实例。
该模式包含以下核心角色:
- Iterator(迭代器接口):定义遍历聚合对象所需的操作,通常包括:
hasNext()
:判断是否还有下一个元素。next()
:返回当前元素并将游标移至下一个。remove()
(可选):移除当前元素(Java 中常见)。
- ConcreteIterator(具体迭代器):实现
Iterator
接口,针对特定聚合结构(如数组、链表)实现具体的遍历逻辑。它持有对聚合对象的引用或内部状态(如索引、当前节点)。 - Aggregate(聚合接口):定义创建迭代器的方法,通常为
createIterator()
。 - ConcreteAggregate(具体聚合类):实现
Aggregate
接口,返回一个与自身结构匹配的ConcreteIterator
实例。 - Client(客户端):通过聚合对象获取迭代器,并使用迭代器接口遍历元素。
迭代器模式的关键优势:
- 解耦聚合与遍历:客户端不依赖聚合的内部结构。
- 支持多种遍历方式:同一聚合可提供多种迭代器(如正序、逆序、过滤迭代器)。
- 简化客户端代码:提供统一的遍历接口。
- 支持并发安全遍历:迭代器可实现“快照”或“失败快速”机制(如 Java 的
ConcurrentModificationException
)。 - 支持延迟计算(Lazy Evaluation):元素可在
next()
调用时动态生成(如数据库游标、无限序列)。
与“访问者模式”相比,迭代器关注线性访问元素,访问者关注在不修改类的前提下为对象结构添加新操作;与“生成器模式”相比,生成器用于创建复杂对象,迭代器用于访问已有对象集合。
迭代器可分为:
- 外部迭代器(External Iterator):客户端主动控制遍历过程(如
while(it.hasNext())
)。 - 内部迭代器(Internal Iterator):由聚合或迭代器内部控制遍历,客户端提供回调(如 Java 8 的
forEach(Consumer)
),更接近“函数式编程”。
二、迭代器模式的UML表示
以下是迭代器模式的标准 UML 类图:
图解说明:
Iterator
定义统一遍历接口。ConcreteIterator
针对ConcreteAggregate
实现具体遍历逻辑。ConcreteAggregate
实现createIterator()
返回其对应的迭代器。Client
通过聚合获取迭代器并遍历。
三、一个简单的Java程序实例及其UML图
以下是一个自定义的 BookShelf
聚合类,使用迭代器模式遍历书架上的书籍。
Java 程序实例
import java.util.ArrayList;
import java.util.List;
// 书籍类
class Book {
private String title;
private String author;
public Book(String title, String author) {
this.title = title;
this.author = author;
}
// Getter 方法
public String getTitle() { return title; }
public String getAuthor() { return author; }
@Override
public String toString() {
return "\"" + title + "\" by " + author;
}
}
// 迭代器接口
interface Iterator<T> {
boolean hasNext();
T next();
}
// 聚合接口
interface Aggregate<T> {
Iterator<T> createIterator();
}
// 具体聚合类:书架
class BookShelf implements Aggregate<Book> {
private List<Book> books = new ArrayList<>();
public void addBook(Book book) {
books.add(book);
}
public int getSize() {
return books.size();
}
public Book getBookAt(int index) {
return books.get(index);
}
// 实现创建迭代器
@Override
public Iterator<Book> createIterator() {
return new BookShelfIterator(this);
}
}
// 具体迭代器:书架迭代器
class BookShelfIterator implements Iterator<Book> {
private BookShelf bookShelf;
private int currentIndex = 0;
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
}
@Override
public boolean hasNext() {
return currentIndex < bookShelf.getSize();
}
@Override
public Book next() {
if (!hasNext()) {
throw new java.util.NoSuchElementException();
}
Book book = bookShelf.getBookAt(currentIndex);
currentIndex++;
return book;
}
}
// 客户端使用示例
public class IteratorPatternDemo {
public static void main(String[] args) {
System.out.println("📚 书架管理系统 - 迭代器模式示例\n");
// 创建书架并添加书籍
BookShelf bookShelf = new BookShelf();
bookShelf.addBook(new Book("设计模式", "GoF"));
bookShelf.addBook(new Book("重构", "Martin Fowler"));
bookShelf.addBook(new Book("代码大全", "Steve McConnell"));
// 获取迭代器
Iterator<Book> iterator = bookShelf.createIterator();
System.out.println("📖 正在遍历书架中的书籍:");
while (iterator.hasNext()) {
Book book = iterator.next();
System.out.println(" ➡️ " + book);
}
System.out.println("\n✅ 遍历完成!");
// 演示:可轻松替换为其他迭代器(如逆序)
// 若实现 ReverseBookShelfIterator,只需替换 createIterator() 返回即可
System.out.println("\n💡 说明:客户端代码无需修改即可支持不同遍历方式。");
System.out.println("🔧 迭代器封装了遍历细节,书架内部可改为链表、树等结构。");
}
}
实例对应的UML图(简化版)
运行说明:
BookShelf
是具体聚合类,内部使用List<Book>
存储书籍。BookShelfIterator
是具体迭代器,持有对BookShelf
的引用和当前索引。- 客户端通过
createIterator()
获取迭代器,使用hasNext()
和next()
安全遍历,无需知道BookShelf
使用List
实现。
四、总结
特性 | 说明 |
---|---|
核心目的 | 统一访问聚合元素,隐藏内部结构 |
实现机制 | 迭代器对象封装遍历状态与逻辑 |
优点 | 解耦、支持多遍历方式、简化客户端、支持延迟计算 |
缺点 | 增加类数量、可能增加内存开销(迭代器对象) |
适用场景 | 集合遍历、树/图遍历、数据库游标、流处理、外部API数据访问 |
不适用场景 | 遍历逻辑极其简单、性能极度敏感(少量元素) |
迭代器模式使用建议:
- Java 集合框架(
Collection
/Iterator
)是迭代器模式的标准实现。 - 可实现只读迭代器、可移除迭代器、过滤迭代器、转换迭代器等变体。
- 支持泛型以提高类型安全。
- 注意并发修改问题,可实现“快照迭代器”或“失败快速”机制。
架构师洞见:
迭代器模式是“关注点分离”与“接口抽象”的典范。在现代架构中,其思想已演变为流式编程(Stream API)、响应式编程(Reactive Streams) 和数据管道的核心。例如,Java 8 的Stream
是迭代器的高级抽象,支持链式操作(filter, map, reduce);在大数据处理中,Iterator
是处理海量数据流的基础(如 Hadoop RecordReader);在微服务中,分页 API 的nextPageToken
本质是分布式迭代器;在前端框架中,虚拟列表(Virtual List)使用迭代器思想按需渲染。未来趋势是:迭代器将与函数式编程深度融合,支持更复杂的组合操作;在AI 数据处理中,数据集迭代器(如 PyTorch DataLoader)是训练模型的关键;在边缘计算中,迭代器可实现低内存的流式数据处理;在量子计算中,状态叠加的遍历可能需要新型迭代器。
掌握迭代器模式,有助于设计出高内聚、低耦合、可复用的集合组件。作为架构师,应在设计任何容器类或数据访问层时,主动考虑使用迭代器。迭代器不仅是模式,更是数据访问的哲学——它告诉我们:真正的抽象,不在于隐藏数据,而在于提供一种安全、统一、可组合的方式来消费数据,让使用者专注于“做什么”,而非“如何做”。