设计模式——Iterator模式
Iterator模式
Java 中可以使用 for 循环语句遍历数组。
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}

这里循环变量 i 的作用抽象化、通用化形成的模式,在设计模式中称为 Iterator 模式。Iterator 被称为 “迭代器”。
示例程序
本示例程序的作用是将书(Book)放置到书架(BookShelf)中,将书的名字按顺序显示出来。

该类类图:

类和接口一览表:
| 名字 | 说明 |
|---|---|
| Aggregate | 表示集合的接口 |
| Iterator | 遍历集合的接口 |
| Book | 表示书的类 |
| BookShelf | 表示书架的类 |
| BookShelfIterator | 遍历书架的类 |
| Main | 测试程序行为的类 |
Aggregate接口
public iterface Aggregate {
public abstract Iterator iterator();
}
如类图所示, Aggregate 接口中声明了一个方法 iterator 聚合了 Iterator 接口。该方法会生成一个抑郁遍历集合的迭代器。
Iterator接口
public interface Iterator {
public abstract boolean hasNext();
public abstract Object next();
}
该接口声明了两个方法:
hasNext:判断是否存在下一个元素next:获取下一个元素
Book类
public class Book {
private String name;
public Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
此类是最基础的类,基本是被应用的类,提供了基础的方法如下:
getName:获取书名构造方法:设置书名
BookShelf类
public class BookShelf implements Aggregate {
private Book[] books;
private int last = 0;
public BookShelf(int maxsize) {
this.books = new Book[maxsize];
}
public Book getBookAt(int index) {
return books[index];
}
public void appendBook(Book book) {
this.books[last] = book;
last++;
}
public int getLength() {
return last;
}
public Iterator iterator() {
return new BookShelfIterator(this);
}
}
该方法引用了较多类和接口,具体关系可以参考类图
BookShelfIterator类
public class BookShelfIterator implements Iterator {
private BookShelf bookShelf;
private int index;
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
this.index = 0;
}
public boolean hasNext() {
if (index < bookShelf.getLength()) {
return true;
} else {
return false;
}
}
public Object next() {
Book book = bookShelf.getBookAt(index);
index++;
return book;
}
}
BookShelfIterator 实现了 Iterator 接口,通过index让循环遍历可以指向下一个下标。
Main
public class Main {
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf(4);
bookShelf.appendBook(new Book("Bible"));
bookShelf.appendBook(new Book("Bible1"));
bookShelf.appendBook(new Book("Bible2"));
bookShelf.appendBook(new Book("Bible3"));
Iterator it = bookShelf.iterator();
while (it.hasNext()) {
Book book = (Book) it.next();
System.out.ptintln(book.getName());
}
}
}
Iterator模式中的登场角色
Iterator 主要有以下角色:
- Iterator(迭代器)
- Concretelterator(具体的迭代器)
- 该角色负责实现 Iterator 角色定义的接口。在示例程序中,由BookShelfIterator类扮演这个角色,它里面定义了
iterator方法。
- 该角色负责实现 Iterator 角色定义的接口。在示例程序中,由BookShelfIterator类扮演这个角色,它里面定义了
- Aggregate(集合)
- ConcreteAggregate(具体的集合)
正常 Iterator 模式的类图:

使用Iterator的要点(为什么使用Iterator)
无论实现如何变化,都可以使用Iterator
为什么不直接使用 for 循环遍历处理呢?而是实现Iterator这个接口呢。
首先,使用 Iterator 可以将遍历与实现分离开:
使用 Iterator:
while (it.hasNext()) {
Book book = (Book) it.next();
System.out.println(book.getName());
}
未使用 Iterator:
for (Book book : books) {
System.out.println(book.getName());
}
在使用Iterator,while循环并不依赖 BookShelf 的实现,如果BookShelf更换 books 的类型为 java.util.Vector,那么 for 将无法工作,需要重新修改逻辑,而使用 iterator 将可以正常工作(前提是hasNext 和 next 方法都可以正常工作)
使用抽象类和接口
通常我们都会使用 ConcreteAggregate 和 ConcreteIterator 编程,也就是具体的类来编程,而不使用 Aggregate 和 Iterator 编程。
如果只使用具体类解决问题,那么类之间将会强耦合,这些类也将难以被二次使用,所以我们需要使用抽象类和接口。
Aggregate和Iterator的对应
如示例程序所示,BookShelfIterator 为 BookShelf 的 ConcreteIterator 橘色。如果 BookShelf 的方法修改,那么 BookShelfIterator 同样需要修改,Aggregate 同理。
容易弄错“下一个”
在 Iterator 模式的实现中,next方法容易出错。该方法的返回值到底是指向当前元素还是当前元素的下一个元素呢?next 方法的名字其实如下:
returnCurrentElementAndAdvanceToNextPosition
也就是说,next方法是 “返回当前的元素,并指向下一个元素”
容易弄错“最后一个”
在 Iterator 模式中,hasNext 方法在返回最后一个元素前会返回true,当返回了最后一个元素后则返回false。
结尾
通过将 BookShelf 的 books 改为 ArrayList,感受一下 Iterator 模式的丝滑和低耦合的爽感:

- 感谢你赐予我前进的力量

