引言:
走进图书馆,你站在一排书架前,想要浏览书籍。你会一格格地从左到右翻阅书籍,而不是去研究书架是什么。
一本书一本书地翻,才知道书架上藏了什么书,研究书架的构造是不知道书籍的内容的。
这种“逐本访问,但不关心内部结构”的方式,正是迭代器模式所解决的问题。
一、什么是迭代器模式
迭代器模式(Iterator Pattern)是一种行为型设计模式,它用于顺序访问一个聚合对象(如集合、数组、列表等)中的元素,而不暴露其内部实现结构。
如同在图书馆看书,你只需一格一格地取书,不必关心书架内部是怎么存放书的。
二、模式结构与角色分工
我们以 Java 中模拟的“书架 BookShelf”为例,来理解迭代器模式的标准结构:
结构角色:
角色 | 作用说明 |
---|---|
Iterator | 定义遍历行为接口,如 hasNext() 和 next() |
ConcreteIterator | 实现具体的遍历逻辑 |
Aggregate | 表示可被遍历的聚合容器 |
ConcreteAggregate | 实现具体容器,如 BookShelf |
Client | 客户端,使用迭代器来遍历聚合对象 |
三、UML 类图(PlantUML)
如下为UML结构图:
四、完整 Java 示例:
实现一个支持迭代的“书架”,来实现书架与书的迭代器。
定义迭代器接口
public interface Iterator<T> {boolean hasNext();T next();
}
定义聚合接口
public interface Aggregate<T> {Iterator<T> createIterator();
}
实体类:书 Book
public class Book {private final String name;public Book(String name) {this.name = name;}public String getName() {return name;}
}
聚合类:书架 BookShelf
public class BookShelf implements Aggregate<Book> {private final Book[] books;private int last = 0;public BookShelf(int maxSize) {books = new Book[maxSize];}public void appendBook(Book book) {books[last++] = book;}public Book getBookAt(int index) {return books[index];}public int getLength() {return last;}@Overridepublic Iterator<Book> createIterator() {return new BookShelfIterator(this);}
}
具体迭代器:BookShelfIterator
public class BookShelfIterator implements Iterator<Book> {private final BookShelf bookShelf;private int index = 0;public BookShelfIterator(BookShelf bookShelf) {this.bookShelf = bookShelf;}@Overridepublic boolean hasNext() {return index < bookShelf.getLength();}@Overridepublic Book next() {return bookShelf.getBookAt(index++);}
}
客户端使用示例
public class Main {public static void main(String[] args) {BookShelf shelf = new BookShelf(5);shelf.appendBook(new Book("Java 入门"));shelf.appendBook(new Book("设计模式"));shelf.appendBook(new Book("数据结构"));Iterator<Book> iterator = shelf.createIterator();while (iterator.hasNext()) {System.out.println(iterator.next().getName());}}
}
五、优点与适用场景
优点
迭代器模式的 5 大优势
优点点名 | 详细说明 |
---|---|
封装遍历逻辑 | 遍历算法被封装在 Iterator 中,不暴露集合内部结构(如数组、链表),提高封装性和模块化。 |
统一遍历接口 | 客户端代码只需依赖统一的 hasNext() + next() 接口,遍历不同类型集合(数组、列表、集合)方式一致,降低学习和使用成本。 |
解耦数据与操作 | 将“存储数据”与“遍历行为”解耦,使集合可以专注于数据存储,迭代器专注于遍历策略。可独立扩展遍历方式,而不破坏集合类结构。 |
支持多种遍历策略 | 可以扩展出不同的迭代器实现,如: 正向遍历 反向遍历 跳步遍历(隔一个取一个) 过滤遍历(如只遍历奇数) |
组合结构遍历利器 | 在树形结构、图结构、目录结构(如菜单、文件系统)中,也能借助迭代器实现统一的访问方式,特别适合组合模式联合使用。 |
适用场景详解
应用情境 | 举例说明 |
---|---|
不想暴露集合内部结构 | 比如使用数组或链表实现的容器,客户端不应访问 books[i] 或 nextNode ,而只应通过迭代器获取元素。 |
希望集合类与遍历逻辑解耦 | 当你需要根据数据源切换不同存储实现时(比如数组 ➜ 链表 ➜ 栈),客户端代码不应受影响,只需提供新的迭代器实现。 |
有多种遍历需求时 | 如:分页展示(一次显示10条)、筛选遍历(只显示评分大于4的书)、逆序浏览等。 |
需要统一接口处理不同容器 | 你希望能一套逻辑遍历多个不同集合对象(如 List、Set、自定义容器),通过统一接口提高代码复用性。 |
希望组合结构对象支持遍历 | 在文件目录、组织架构树、菜单栏中,想要统一地“层层展开浏览”,迭代器是组合模式的理想搭档。 |
开发脚本解释器、编译器 | 语言处理器中常常要遍历语法树(AST),语法元素集合可以通过迭代器统一访问,提高程序可扩展性。 |
六、在JDK 的使用
Java 中的 java.util.Iterator
就是这个模式的原生体现:
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");Iterator<String> it = list.iterator();
while (it.hasNext()) {System.out.println(it.next());
}
只需要关注 元素如何一个个访问,而不关心其他因素。
总结
项目 | 内容 |
---|---|
模式名称 | 迭代器模式(Iterator Pattern) |
类型 | 行为型模式 |
典型用途 | 遍历集合,不暴露内部结构 |
Java 支持 | java.util.Iterator 接口 |
类比说明 | 一本本地翻阅图书馆书架上的书 |
参考
《23种设计模式概览》