1、Iterator模式
使用java语言显示数组arr中的元素时,我们可以使用下面这样的for循环语句来遍历数组。
for (int i = 0,l = arr.length; i < l; i++){
System.out.println(arr[i]);
}
请注意这段代码中的循环变量i。该变量的初始值是0,然后会递增为1,2,3,。。。,程序则在每次i递增后都会输出arr[i]。我们在程序中会经常看到这样的for循环语句。
for语句中的i++的作用是让i的值在每次循环后自增1,这样就可以访问数组中的下一个元素、下下一个元素、再下下一个元素,也就实现了从头到尾逐一遍历数组元素的功能。
将这里的循环变量i的作用抽象化,通用化后形成的模式,在设计模式中称为Iterator模式。Iterator模式用于在数据集合中按照顺序遍历集合。英语单词Iterator有反复做某件事情的意思,汉语称为“迭代器”。我们将在本篇文章中学习Iterator模式。
2、示例程序
首先,让我们来看一段实现了Iterator模式的示例程序。这段示例程序的作用是将书(Book)放置到书架(BookShelf)中,并将书的名字按顺序显示出来。
Aggregate接口
Aggregate接口是所要遍历的集合的接口。实现了该接口的类将成为一个可以保存多个元素的集合,就像数组一样。Aggregate有“使聚集“”集合“的意思。
public interface Aggregate {
/**
* 生成一个用于遍历集合的迭代器
* @return
*/
public abstract Iterator iterator();
}
在Aggregate接口中声明的方法只有一个————Iterator方法。该方法会生成一个用于遍历集合的迭代器。
想要遍历集合中的元素时,可以调用iterator方法来生成一个实现了Iterator接口的类的示例。
Iterator接口
public interface Iterator {
/**
* 判断是否存在下一个元素
* @return
*/
public abstract boolean hasNext();
/**
*获取下一个元素
* @return
*/
public abstract Object next();
}
这里我们声明了两个方法,即判断是否存在下一个元素的hasNext方法,和获取下一个元素的next方法。
hasNext方法的返回值是boolean类型的,其原因很容易理解。当集合中存在下一个元素时,该方法返回true,反之,返回false。hasNext方法主要用于循环终止条件。
这里有必要说明一下next方法。该方法返回的类型是Object,这表明该方法返回的是集合中的一个元素。但是,next方法的作用并非仅仅如此。为了能够在下次调用next方法时正确地返回下一个元素,该方法还隐含着将迭代器移动至下一个元素的处理。
Book类
public class Book {
private String name;
public Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Book类表示书的类,但是这个类的作用有限,他可以做的事情只有一件————通过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;
}
@Override
public Iterator iterator() {
return new BookShelfIterator(this);
}
}
BookShelf类是表示书架的类。由于需要将该类作为集合进行处理,因此他实现了Aggregate接口。这个书架中定义了books字段,他是Book类型的数组。iterator方法会生成并返回BookShelfIterator类的实例作为BookShelf类对应的Iterator。当外部想要遍历书架时,就会调用这个方法。
BookShelfIterator类
public class BookShelfIterator implements Iterator {
private BookShelf bookShelf;
private int index;
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
this.index = 0;
}
@Override
public boolean hasNext() {
return index < bookShelf.getLength() ? true : false;
}
@Override
public Object next() {
Book book = bookShelf.getBookAt(index);
index++;
return book;
}
}
因为BookShelfIterator类需要发挥Iterator的作用,所以他实现了Iterator接口。
bookShelf字段表示BookShelfIterator所要遍历的书架。index字段表示迭代器当前所指向的书的下标。
Main类
public class Main {
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf(5);
bookShelf.appendBook(new Book("Java"));
bookShelf.appendBook(new Book("c++"));
bookShelf.appendBook(new Book("c"));
bookShelf.appendBook(new Book("sql"));
bookShelf.appendBook(new Book("php"));
Iterator iterator = bookShelf.iterator();
while (iterator.hasNext()){
Book book = (Book) iterator.next();
System.out.println(book.getName());
}
}
}
这段程序首先设计了一个能容纳5本书的书架,然后添加了5本书。最后通过bookShelf.iterator()得到的iterator是用于遍历书架的Iterator实例。最后循环遍历输出书的名字。
下图是上面这段代码的运行结果
3、Iterator模式中的登场角色
Iterator(迭代器)
该角色负责定义按顺序逐个遍历元素的接口(API)。在示例程序中,由Iterator接口扮演这个角色,他定义了hasNext和 next两个方法。其中,hasNext方法用于判断是否存在下一个元素,next方法则用于获取该元素。
ConcreteIterator(具体的迭代器)
Aggregate(集合)
该角色负责定义创建 Iterator 角色的接口(API)。这个接口是一个方法,会创建出“按顺序访问保存在我内部元素的人”。在示例程序中,由Aggregate 接口扮演这个角色,它里面定义了 iterator 方法。ConcreteAggregate(具体的集合)
该角色负责实现 Aggregate 角色所定义的接口(API) 。它会创建出具体的 Iterator角色,即 ConcreteIterator 。在示例程序中,由BookShelf 类扮演这个角色,它实现了iterator 方法。
下图展示了Iterator模式的类图