迭代器模式(Iterator Pattern)
迭代器模式是一种行为型设计模式,它提供了一种统一的方法来顺序访问聚合对象(如集合、容器)中的元素,而无需暴露聚合对象的内部结构。这种模式将 “遍历元素” 的行为与 “存储元素” 的聚合对象分离,使得遍历逻辑可以独立于聚合结构变化。
一、定义
官方定义:提供一种方法访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。
通俗理解:迭代器模式就像一本书的目录 —— 读者无需知道书的内页是如何装订的(内部结构),只需通过目录(迭代器)按顺序翻阅每一页(元素)。例如,Java 中的 Iterator 就是迭代器模式的典型实现,无论集合是 ArrayList(数组结构)还是 LinkedList(链表结构),都可以通过 Iterator 统一遍历。
二、意图
- 解耦聚合与遍历:让聚合对象(如集合)专注于存储数据,将遍历元素的逻辑交给迭代器,两者独立变化。
- 统一遍历接口:为不同结构的聚合对象提供一致的遍历方式(如
hasNext()、next()),简化客户端使用。 - 支持多种遍历方式:一个聚合对象可以有多个迭代器,分别实现不同的遍历逻辑(如正向遍历、反向遍历、过滤遍历)。
- 隐藏内部结构:客户端无需知道聚合对象的内部实现(如数组、链表、树),只需通过迭代器访问元素。
三、结构
迭代器模式包含4 个核心角色,各角色协同实现 “存储” 与 “遍历” 的分离:
| 角色名称 | 核心职责 |
|---|---|
| 抽象迭代器(Iterator) | 定义遍历元素的接口,通常包含: - hasNext():判断是否还有下一个元素; - next():获取下一个元素; - (可选)remove():移除当前元素。 |
| 具体迭代器(ConcreteIterator) | 实现抽象迭代器接口,持有聚合对象的引用,记录当前遍历位置,完成实际的遍历逻辑。 |
| 抽象聚合(Aggregate) | 定义创建迭代器的接口(如 createIterator()),是聚合对象的抽象表示。 |
| 具体聚合(ConcreteAggregate) | 实现抽象聚合接口,存储元素,返回具体迭代器实例(与自身匹配的迭代器)。 |
四、优点
- 分离职责:聚合对象负责存储数据,迭代器负责遍历数据,符合 “单一职责原则”。
- 统一接口:不同结构的聚合对象(数组、链表、树)可通过相同的迭代器接口遍历,简化客户端代码。
- 支持多遍历:一个聚合对象可创建多个不同的迭代器,实现多种遍历方式(如正向、反向、过滤)。
- 隐藏内部结构:客户端无需了解聚合对象的内部实现(如
ArrayList的数组、LinkedList的链表),降低耦合。 - 便于扩展:新增聚合类型时,只需实现对应的迭代器;新增遍历方式时,只需新增迭代器,符合 “开闭原则”。
五、缺点
- 类数量增加:每个聚合对象可能需要对应一个迭代器,导致系统中类的数量增加,增加维护成本。
- 迭代器与聚合耦合:具体迭代器依赖于具体聚合的内部结构(如迭代器需要知道聚合是数组还是链表),两者耦合度较高。
- 简单场景冗余:对于简单的聚合对象(如固定大小的数组),直接遍历可能比使用迭代器更简洁,此时使用迭代器模式会显得过度设计。
- 并发问题:若聚合对象在迭代过程中被修改(如添加 / 删除元素),迭代器可能会出现异常(如 Java 的
ConcurrentModificationException)。
六、类图(Mermaid)

以 “书架(BookShelf)存储书籍(Book)” 为例,类图展示迭代器模式的结构:
classDiagram
direction TB
class Iterator {
<<interface>>
+hasNext(): boolean
+next(): Object
}
class BookShelfIterator {
-bookShelf: BookShelf
-index: int
+BookShelfIterator(bookShelf: BookShelf)
+hasNext(): boolean
+next(): Book
}
class Aggregate {
<<interface>>
+createIterator(): Iterator
}
class BookShelf {
-books: Book[]
-size: int
+BookShelf(maxSize: int)
+addBook(book: Book): void
+getBookAt(index: int): Book
+getSize(): int
+createIterator(): Iterator
}
class Book {
-name: String
+Book(name: String)
+getName(): String
}
class Client {
+main(): void
}
Iterator <|.. BookShelfIterator
Aggregate <|.. BookShelf
BookShelfIterator o-- BookShelf : "持有"
BookShelf o-- Book : "包含"
Client --> BookShelf : "创建并使用"
Client --> Iterator : "通过迭代器遍历"
七、时序图(Mermaid)
以下时序图展示客户端通过迭代器遍历书架中书籍的过程:
sequenceDiagram
participant Client
participant BookShelf as 具体聚合(书架)
participant BookShelfIterator as 具体迭代器
participant Book as 书籍(元素)
%% 1. 客户端创建聚合对象并添加元素
Client->>BookShelf: 1. 创建书架(new BookShelf(3))
Client->>Book: 2. 创建书籍1(《设计模式》)
Client->>BookShelf: 3. 添加书籍1(addBook(book1))
Client->>Book: 4. 创建书籍2(《Java编程》)
Client->>BookShelf: 5. 添加书籍2(addBook(book2))
%% 2. 客户端获取迭代器
Client->>BookShelf: 6. 获取迭代器(createIterator())
BookShelf->>BookShelfIterator: 7. 创建迭代器(new BookShelfIterator(this))
BookShelfIterator-->>BookShelf: 8. 返回迭代器实例
BookShelf-->>Client: 9. 返回迭代器给客户端
%% 3. 客户端通过迭代器遍历元素
loop 遍历所有书籍
Client->>BookShelfIterator: 10. 调用 hasNext()
BookShelfIterator-->>Client: 11. 返回 true(还有下一本书)
Client->>BookShelfIterator: 12. 调用 next()
BookShelfIterator->>BookShelf: 13. 获取当前书籍(getBookAt(index))
BookShelf->>Book: 14. 返回书籍对象
Book-->>BookShelfIterator: 15. 返回书籍
BookShelfIterator-->>Client: 16. 返回书籍给客户端
Client->>Book: 17. 打印书籍名称(getName())
end
Client->>BookShelfIterator: 18. 再次调用 hasNext()
BookShelfIterator-->>Client: 19. 返回 false(无更多书籍)
八、适用环境
当系统满足以下场景时,适合使用迭代器模式:
- 需要遍历聚合对象,但不希望暴露其内部结构:如封装自定义集合(如树形结构、图结构),隐藏实现细节。
- 需要统一不同聚合对象的遍历接口:如同时使用数组、链表、哈希表时,通过相同的迭代器接口遍历。
- 需要多种遍历方式:如对一个集合同时需要正向遍历、反向遍历、按条件过滤遍历。
- 聚合对象的内部结构可能变化:通过迭代器隔离遍历逻辑,当聚合内部结构改变时,只需修改迭代器,无需修改客户端。
九、模式分析
- 核心逻辑:迭代器模式的本质是 “封装遍历”—— 将遍历元素的逻辑从聚合对象中抽离,形成独立的迭代器对象,使两者可以独立演化。
- 迭代器的类型:
- 内部迭代器:迭代器控制遍历过程(如 Java 8 的
forEach),客户端只需提供处理逻辑,无需关心遍历步骤。 - 外部迭代器:客户端控制遍历过程(如 Java 的
Iterator),通过hasNext()和next()手动推进遍历,灵活性更高。
- 内部迭代器:迭代器控制遍历过程(如 Java 8 的
- 与集合的关系:迭代器是集合的 “访问接口”,集合必须提供创建迭代器的方法;迭代器依赖集合的内部结构才能正确遍历(如数组的索引、链表的指针)。
- 删除元素的注意事项:迭代器的
remove()方法需谨慎实现,需确保删除后不影响后续遍历(如 Java 迭代器的remove()必须在next()之后调用)。
十、模式扩展
迭代器模式可根据业务需求扩展出多种变体:
- 双向迭代器(Bidirectional Iterator):支持向前和向后遍历,增加
hasPrevious()和previous()方法(如 Java 的ListIterator)。 - 跳跃迭代器(Jump Iterator):支持跳过指定数量的元素(如
skip(n)方法),适用于大数据集的快速定位。 - 过滤迭代器(Filter Iterator):遍历过程中只返回符合条件的元素(如
next(predicate),只返回满足 predicate 的元素)。 - 懒加载迭代器(Lazy Iterator):按需加载元素(如分页查询时,只在调用
next()时才加载下一页数据),减少内存占用。 - 并发迭代器(Concurrent Iterator):支持在迭代过程中安全修改聚合对象(如采用快照机制,避免
ConcurrentModificationException)。
十一、模式应用
迭代器模式是编程语言和框架中最常用的设计模式之一,典型应用包括:
- 编程语言集合框架:
- Java:
java.util.Iterator接口(ArrayList、HashMap等集合的迭代器实现)。 - C#:
IEnumerator接口(List、Dictionary等的迭代器)。 - Python:迭代器协议(
__iter__()和__next__()方法),支持for循环遍历。 - C++:
STL中的iterator(如vector::iterator、list::iterator)。
- Java:
- 数据库查询结果遍历:
- JDBC 的
ResultSet:通过next()方法遍历查询结果,本质是迭代器模式。 - Android 的
Cursor:遍历数据库查询结果,moveToNext()类似hasNext()+next()。
- JDBC 的
- 自定义集合遍历:
- 树形结构(如二叉树)的迭代器(前序、中序、后序遍历)。
- 图结构的迭代器(深度优先、广度优先遍历)。
十二、Android 中的应用
在 Android 开发中,迭代器模式的应用广泛,以下是典型场景:
Java 集合框架的应用: Android 基于 Java 生态,直接使用 Java 集合框架的迭代器,如:
List<String> list = new ArrayList<>(); // 添加元素... Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String item = iterator.next(); // 处理元素 }Cursor 遍历数据库结果: 查询 SQLite 数据库时,
Cursor扮演迭代器角色,遍历查询结果:Cursor cursor = db.query("users", null, null, null, null, null, null); while (cursor.moveToNext()) { // 类似 hasNext() + next() String name = cursor.getString(cursor.getColumnIndex("name")); // 处理数据 } cursor.close();RecyclerView 数据遍历:
RecyclerView.Adapter中的数据遍历逻辑本质上依赖迭代器思想,getItemCount()和onBindViewHolder()配合完成数据到视图的映射,相当于 “隐式迭代器”。自定义集合迭代: 开发中若需自定义数据结构(如树形菜单、多级列表),可通过迭代器模式封装遍历逻辑,简化 UI 渲染代码。
十三、代码实现(Java 版)
以 “书架存储书籍” 为例,实现迭代器模式,支持正向遍历书籍:
1. 抽象迭代器(Iterator)
// 抽象迭代器:定义遍历接口
public interface Iterator {
// 判断是否有下一个元素
boolean hasNext();
// 获取下一个元素
Object next();
}
2. 抽象聚合(Aggregate)
// 抽象聚合:定义创建迭代器的接口
public interface Aggregate {
Iterator createIterator();
}
3. 具体元素(Book)
// 具体元素:书籍
public class Book {
private String name; // 书名
public Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
4. 具体聚合(BookShelf)
// 具体聚合:书架(存储书籍)
public class BookShelf implements Aggregate {
private Book[] books; // 用数组存储书籍(内部结构)
private int size; // 当前书籍数量
// 初始化书架容量
public BookShelf(int maxSize) {
this.books = new Book[maxSize];
this.size = 0;
}
// 添加书籍
public void addBook(Book book) {
if (size < books.length) {
books[size] = book;
size++;
} else {
System.out.println("书架已满,无法添加书籍:" + book.getName());
}
}
// 获取指定位置的书籍(供迭代器使用)
public Book getBookAt(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("索引越界:" + index);
}
return books[index];
}
// 获取书籍数量
public int getSize() {
return size;
}
// 创建并返回迭代器
@Override
public Iterator createIterator() {
return new BookShelfIterator(this);
}
}
5. 具体迭代器(BookShelfIterator)
// 具体迭代器:书架迭代器(遍历书籍)
public class BookShelfIterator implements Iterator {
private BookShelf bookShelf; // 持有书架引用
private int index; // 当前遍历位置
// 初始化迭代器,从第0个元素开始
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
this.index = 0;
}
// 判断是否还有下一本书
@Override
public boolean hasNext() {
return index < bookShelf.getSize();
}
// 获取下一本书,并移动索引
@Override
public Object next() {
Book book = bookShelf.getBookAt(index);
index++;
return book;
}
}
6. 客户端(Client)
// 客户端:使用迭代器遍历书架
public class Client {
public static void main(String[] args) {
// 1. 创建书架(容量为3)
BookShelf bookShelf = new BookShelf(3);
// 2. 向书架添加书籍
bookShelf.addBook(new Book("《设计模式:可复用面向对象软件的基础》"));
bookShelf.addBook(new Book("《Java编程思想》"));
bookShelf.addBook(new Book("《Android开发艺术探索》"));
bookShelf.addBook(new Book("《多余的书》")); // 书架已满,添加失败
// 3. 获取迭代器并遍历
Iterator iterator = bookShelf.createIterator();
System.out.println("书架中的书籍:");
while (iterator.hasNext()) {
Book book = (Book) iterator.next();
System.out.println("- " + book.getName());
}
}
}
7. 运行结果
书架已满,无法添加书籍:《多余的书》
书架中的书籍:
- 《设计模式:可复用面向对象软件的基础》
- 《Java编程思想》
- 《Android开发艺术探索》
十四、总结
迭代器模式通过分离 “聚合对象” 与 “遍历逻辑”,提供了一种统一、灵活的元素访问方式,其核心价值在于:
- 解耦存储与遍历:聚合对象专注于数据存储,迭代器专注于遍历逻辑,两者独立演化,降低耦合。
- 统一遍历接口:无论聚合内部是数组、链表还是其他结构,客户端都可通过相同的迭代器接口访问,简化使用。
- 支持多维度扩展:新增聚合类型只需实现对应的迭代器;新增遍历方式只需新增迭代器,符合 “开闭原则”。
在实际开发中,迭代器模式已被编程语言的集合框架广泛采用(如 Java 的 Iterator),开发者无需重复实现基础迭代逻辑。但在自定义复杂数据结构(如树、图)时,手动实现迭代器模式能有效隐藏内部结构,简化遍历逻辑。
需注意避免过度设计:对于简单聚合(如固定大小的数组),直接遍历可能更简洁;同时需处理迭代过程中聚合对象的修改问题(如采用快速失败机制)。
总之,迭代器模式是 “封装变化” 思想的典型体现,是处理集合遍历问题的标准解决方案。