设计模式之适应设计模式_Iterator模式_只关心遍历不关心怎么存
一、Iterator(迭代器)设计模式
1、示例场景
将多本书(
Book)放入书架(BookShelf),然后通过 迭代器(Iterator) 遍历并打印每本书的名称。
该示例展示了如何使用 Iterator 模式 实现对集合元素的安全、统一遍历,同时 解耦遍历逻辑与集合内部实现。
2、UML 图

3、代码实现
1)Aggregate 接口:集合抽象(相当于 Iterable)
/**
* 集合接口(Aggregate)
* 定义创建迭代器的方法
*/
public interface Aggregate {
Iterator iterator();
}
2)Iterator 接口:迭代器抽象
/**
* 迭代器接口
* 提供统一的遍历方式
*/
public interface Iterator {
boolean hasNext(); // 是否还有下一个元素
Object next(); // 返回下一个元素
}
3)Book 类:数据模型
import lombok.Data;
import lombok.AllArgsConstructor;
@Data
@AllArgsConstructor
public class Book {
private String name;
}
4)BookShelf 类:具体集合(ConcreteAggregate)
import java.util.ArrayList;
import java.util.List;
/**
* 书架类 —— 具体的聚合体(ConcreteAggregate)
* 内部使用 List 存储书籍,但对外隐藏实现细节
*/
public class BookShelf implements Aggregate {
private final List<Book> books = new ArrayList<>();
// 可选:用 size 记录数量(也可直接用 books.size())
private int size = 0;
public void appendBook(Book book) {
books.add(book);
size++;
}
public Book getBookAt(int index) {
return books.get(index);
}
public int getLength() {
return size; // 或 return books.size();
}
@Override
public Iterator iterator() {
return new BookShelfIterator(this);
}
}
5)BookShelfIterator 类:具体迭代器(ConcreteIterator)
/**
* 书架迭代器 —— 具体的迭代器(ConcreteIterator)
*/
public class BookShelfIterator implements Iterator {
private final BookShelf bookShelf;
private int index = 0;
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
}
@Override
public boolean hasNext() {
return index < bookShelf.getLength();
}
@Override
public Object next() {
if (!hasNext()) {
throw new IllegalStateException("No more elements");
}
Book book = bookShelf.getBookAt(index);
index++; // 移动到下一个位置
return book;
}
}
6) 测试类 Main
public class Main {
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf();
bookShelf.appendBook(new Book("Around the World in 80 Days"));
bookShelf.appendBook(new Book("Bible"));
bookShelf.appendBook(new Book("Cinderella"));
bookShelf.appendBook(new Book("Daddy-Long-Legs"));
Iterator it = bookShelf.iterator();
while (it.hasNext()) {
Book book = (Book) it.next();
System.out.println(book.getName());
}
}
}
4、Iterator 模式中的角色
| 角色 | 说明 | 示例 |
|---|---|---|
Aggregate(抽象集合) |
定义创建迭代器的接口 | Aggregate 接口 |
ConcreteAggregate(具体集合) |
实现 Aggregate,提供具体迭代器 |
BookShelf |
Iterator(抽象迭代器) |
定义遍历接口(hasNext, next) |
Iterator 接口 |
ConcreteIterator(具体迭代器) |
实现遍历逻辑,持有对集合的引用 | BookShelfIterator |

5、FQA
1)为什么需要 Iterator?—— 核心价值
答案:解耦遍历逻辑与集合实现
- 客户端代码 只依赖
Iterator接口,不关心集合是ArrayList、数组、链表还是自定义结构。 - 即使
BookShelf内部从List改为 普通数组、树结构 或 远程数据库查询,只要iterator()方法返回合法的Iterator,客户端代码无需任何修改!
// 客户端代码完全不变!
Iterator it = bookShelf.iterator();
while (it.hasNext()) {
Book book = (Book) it.next();
System.out.println(book.getName());
}
这就是“面向接口编程”和“开闭原则”的体现:对扩展开放,对修改关闭。
2)误区:next() 的语义
next()返回的是“当前”元素,然后 移动指针到下一个位置。- 初学者常误以为
next()返回“下一个”元素(其实是指针移动后的“新当前”)。
初始: index = 0
调用 next() → 返回 books[0],index 变为 1
再调用 next() → 返回 books[1],index 变为 2
...
3)误区:缺少边界检查
- 应在
next()中校验是否还有元素,避免越界。 - 最佳实践:先调用
hasNext(),再调用next()。
4)误区:类型安全问题
- 当前使用
Object返回值,需强制类型转换,存在风险。 - 优化建议:使用 泛型 提升类型安全(见下文)。
public interface Iterator<T> {
boolean hasNext();
T next();
}
public interface Aggregate<T> {
Iterator<T> iterator();
}
public class BookShelfIterator implements Iterator<Book> { ... }
public class BookShelf implements Aggregate<Book> { ... }
Iterator<Book> it = bookShelf.iterator();
while (it.hasNext()) {
Book book = it.next(); // 无需强制转换!
System.out.println(book.getName());
}
3、扩展思路
Book数组我们直接for循环打印出来不久好了,为啥还要使用Iterator这个东西呢 ,
原因:引入Iterator后可以讲遍历与实现分离开来 ,不管实现如何变化,都可以使用Iterator,这里只使用了Iterator的hasNext方法和next方法,并没有调用BookShelf方法,也就是说While循环不依赖BookShelf的实现
举例:如果编写BookShel 书架的开发人员觉得不使用List集合来管理书本,而是使用其他的,比如使用数据来管理书本,,这样的话,不管书架 BookShel如何变化,只要BootShelf的iterator的方法能够正确返回Iterator的实例 即使不对while做任何修改,代码都可以正常工作。
Iterator it = bookShelf.iterator();
while (it.hasNext()) {
Book book = (Book)it.next();
System.out.println(book.getName());
}
4、容易出错的地方
4.1、容易容错下一个,很容易在next方法上出错, next方法是,返回当前的元素,index指向下一个元素


