迭代器模式
迭代器模式:统一集合遍历的设计艺术
一、迭代器模式的定义与核心思想
迭代器模式(Iterator Pattern) 是一种行为型设计模式,它提供一种方法顺序访问一个聚合对象(如集合、容器)中的各个元素,而无需暴露该对象的内部表示。其核心思想是 “分离集合的遍历逻辑与集合本身”,通过引入独立的迭代器对象,封装遍历细节,让集合类专注于元素的存储与管理,迭代器专注于元素的访问顺序控制。
简单来说,迭代器模式解决了 “如何不暴露集合内部结构,同时提供统一遍历方式” 的问题。例如,Java 中的 Iterator 接口、Python 中的 for...in 循环底层,都采用了迭代器模式的设计思想。
二、迭代器模式的角色构成
迭代器模式通常包含以下 4 个核心角色,各角色职责明确、分工协作:
| 角色名称 | 核心职责 | 示例(Java 场景) |
|---|---|---|
| 抽象聚合类(Aggregate) | 定义创建迭代器对象的接口,声明集合的基本操作(如添加、删除元素) | List 接口 |
| 具体聚合类(ConcreteAggregate) | 实现抽象聚合类,存储元素集合,并重写创建迭代器的方法,返回对应具体迭代器实例 | ArrayList 类 |
| 抽象迭代器(Iterator) | 定义遍历元素的接口,包含核心方法:hasNext()(判断是否有下一个元素)、next()(获取下一个元素) |
Iterator 接口 |
| 具体迭代器(ConcreteIterator) | 实现抽象迭代器接口,记录当前遍历位置,封装具体的遍历逻辑(如顺序、逆序) | ArrayList 内部的 Itr 类 |
三、迭代器模式的工作原理与实现示例
1. 工作流程
-
客户端请求具体聚合类创建迭代器实例;
-
客户端通过迭代器的
hasNext()方法判断是否还有未遍历的元素; -
若有,通过
next()方法获取下一个元素并进行处理; -
重复步骤 2-3,直至遍历完所有元素。
2. 代码实现(Java 示例)
以 “图书集合” 为例,实现一个支持顺序遍历的迭代器模式:
(1)抽象迭代器接口(Iterator)
// 抽象迭代器:定义遍历接口
public interface BookIterator {
boolean hasNext(); // 判断是否有下一本书
Book next(); // 获取下一本书
}
(2)抽象聚合类(Aggregate)
// 抽象聚合类:定义集合操作与创建迭代器的接口
public interface BookCollection {
void addBook(Book book); // 添加图书
void removeBook(Book book); // 删除图书
BookIterator createIterator(); // 创建迭代器
}
(3)具体元素类(Book)
// 集合中的元素:图书类
public class Book {
private String name; // 书名
private String author; // 作者
public Book(String name, String author) {
this.name = name;
this.author = author;
}
// getter/setter 省略
@Override
public String toString() {
return "《" + name + "》(作者:" + author + ")";
}
}
(4)具体聚合类(ConcreteAggregate)
// 具体聚合类:图书集合(基于数组存储)
public class ConcreteBookCollection implements BookCollection {
private Book[] books;
private int size = 0; // 当前图书数量
private static final int DEFAULT_CAPACITY = 10; // 默认容量
public ConcreteBookCollection() {
this.books = new Book[DEFAULT_CAPACITY];
}
@Override
public void addBook(Book book) {
if (size >= books.length) {
// 扩容逻辑(简化实现)
Book[] newBooks = new Book[books.length * 2];
System.arraycopy(books, 0, newBooks, 0, books.length);
books = newBooks;
}
books[size++] = book;
}
@Override
public void removeBook(Book book) {
for (int i = 0;i<books.length;i ++) {
if (books[i].equals(book)) {
// 移除元素:后续元素前移
System.arraycopy(books, i+1, books, i, size - i - 1);
books[--size] = null;
break;
}
}
}
@Override
public BookIterator createIterator() {
// 返回具体迭代器,传入当前集合的元素数组和大小
return new ConcreteBookIterator(books, size);
}
}
(5)具体迭代器类(ConcreteIterator)
// 具体迭代器:实现图书集合的顺序遍历
public class ConcreteBookIterator implements BookIterator {
private Book[] books;
private int size;
private int currentIndex = 0; // 当前遍历索引
public ConcreteBookIterator(Book[] books, int size) {
this.books = books;
this.size = size;
}
@Override
public boolean hasNext() {
// 条件:1. 当前索引未超出集合实际大小 2. 当前位置元素不为空
return currentIndex < size && books[currentIndex] != null;
}
@Override
public Book next() {
if (!hasNext()) {
throw new NoSuchElementException("没有更多图书了");
}
return books[currentIndex++]; // 返回当前元素并移动索引
}
}
(6)客户端调用示例
public class Client {
public static void main(String[] args) {
// 1. 创建具体聚合对象(图书集合)
BookCollection bookCollection = new ConcreteBookCollection();
// 2. 向集合添加元素
bookCollection.addBook(new Book("设计模式", " Erich Gamma"));
bookCollection.addBook(new Book("Java编程思想", "Bruce Eckel"));
bookCollection.addBook(new Book("深入理解Java虚拟机", "周志明"));
// 3. 获取迭代器并遍历
BookIterator iterator = bookCollection.createIterator();
System.out.println("图书列表:");
while (iterator.hasNext()) {
Book book = iterator.next();
System.out.println(book);
}
}
}
输出结果
图书列表:
《设计模式》(作者:Erich Gamma)
《Java编程思想》(作者:Bruce Eckel)
《深入理解Java虚拟机》(作者:周志明)
四、迭代器模式的应用场景
迭代器模式适用于以下场景:
-
需要统一遍历不同结构的集合:例如,无论集合是数组、链表、哈希表,都通过相同的
hasNext()/next()方法遍历,降低客户端学习成本。 -
不希望暴露集合内部实现:客户端无需知道集合是基于数组还是链表存储,只需通过迭代器访问元素,符合 “封装” 原则。
-
需要灵活切换遍历方式:例如,同一集合可支持顺序遍历、逆序遍历、过滤遍历(如只遍历偶数元素),只需创建不同的具体迭代器即可。
-
集合类职责单一:集合类仅负责元素的增删改查,遍历逻辑交给迭代器,符合 “单一职责原则”。
五、迭代器模式的优缺点
优点
-
解耦遍历与集合:遍历逻辑独立于集合,集合修改(如更换存储结构)时,无需修改客户端遍历代码。
-
统一遍历接口:不同集合的遍历方式标准化,客户端代码更简洁、易维护。
-
支持多种遍历方式:可通过扩展具体迭代器,实现同一集合的不同遍历逻辑(如顺序、逆序、过滤)。
-
符合设计原则:遵循 “单一职责原则”(集合管存储,迭代器管遍历)和 “开闭原则”(新增遍历方式无需修改原有代码)。
缺点
-
增加类的数量:每新增一个集合类,可能需要对应新增一个迭代器类,增加了系统的复杂性。
-
遍历过程中修改集合需谨慎:若遍历过程中对集合进行增删操作,可能导致迭代器状态混乱(如漏遍历、重复遍历),需额外处理并发问题(如快速失败机制)。
-
简单集合场景下冗余:对于结构简单的集合(如固定大小的数组),直接遍历可能比引入迭代器更高效。

浙公网安备 33010602011771号