设计模式 —— Iterator(迭代器) 模式
Iterator模式简介
试想一下,我们在获取一个数组中的元素时,一般会使用for循环语句遍历数组,i++的作用是让 i 的值在每次循环后自增1,这样就可以依次访问数组中的下一个元素,也就实现了从头至尾逐一遍历数组元素的功能。
for (int i = 0; i < arr.length;i++) {
System.out.println(arr[i]);
}
将 i 的作用抽象化,通用化后形成的模式,就称为Iterator模式。Iterator模式用于在数据集合中按照顺序遍历集合。
示例程序
来想一个简单的问题,假如有一些书本,这些书本需要放在书架中,这样我们就可以很方便的管理这些书,现在需要将书架上的书的名字按顺序显示出来,用Iterator模式来实现。
Aggregate接口
这里把所有类似书架(BookShelf)这样的,用于存放物品的容器抽象出一个Aggregate接口,里面只有一个获取Iterator的方法,书架(BookShelf)需要实现这个接口。
public interface Aggregate {
/**
* 用于遍历集合的迭代器
*/
public abstract Iterator iterator();
}
Iterator接口
Iterator接口用来遍历集合中的元素,其中有判断是否存在下一个元素的hasNext方法,和获取下一个元素的next方法。
public interface Iterator {
/**
* 判断是否存在下一个元素
*/
public abstract boolean hasNext();
/**
*获取下一个元素
*/
public abstract Object next();
}
Book类
Book类用来表示书本,它在这里比较简单,里面只有一个获取名字的方法。
public class Book {
private String name;
public Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
BookShelf类
BookShelf类用来表示书架,因为它是一个容器,所以要求实现Aggregate接口。这里实现了Aggregate接口的iterator方法,该方法会生成并返回一个BookShelfIterator类的实例,当外部想要遍历书架时,就会调用这个方法。
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);
}
}
BookShelfIterator类
BookShelfIterator类用来表示遍历书架的类,它实现了Iterator类。bookShelf字段表示BookShelfIterator所要遍历的书架。index字段表示迭代器当前所指向的书的下标。
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;
}
}
Main类
public class Main {
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf(5);
bookShelf.appendBook(new Book("A"));
bookShelf.appendBook(new Book("B"));
bookShelf.appendBook(new Book("C"));
bookShelf.appendBook(new Book("D"));
bookShelf.appendBook(new Book("E"));
Iterator iterator = bookShelf.iterator();
while (iterator.hasNext()){
Book book = (Book) iterator.next();
System.out.println(book.getName());
}
}
}
Iterator模式中的角色
Iterator(迭代器)
该角色负责定义按顺序逐个遍历元素的接口(API)。在示例程序中,由Iterator接口扮演这个角色,他定义了hasNext和 next两个方法。其中,hasNext方法用于判断是否存在下一个元素,next方法则用于获取该元素。
ConcreteIterator(具体的迭代器)
该角色负责实现Iterator角色所定义的接口(API)。在示例程序中,BookShelfIterator 类扮演这个角色。该角色中包含了遍历集合所必需的信息。在示例程序中 BookShelf 类的实例保存在 bookShelf 字段中,被指向的书的下标保存在 index 字段中。
Aggregate(集合)
该角色负责定义创建 Iterator 角色的接口(API)。这个接口是一个方法,会创建出“按顺序访问保存在我内部元素的人”。在示例程序中,由Aggregate 接口扮演这个角色,它里面定义了 iterator 方法。
ConcreteAggregate(具体的集合)
该角色负责实现 Aggregate 角色所定义的接口(API)。它会创建出具体的 Iterator角色,即 ConcreteIterator 。在示例程序中,由BookShelf 类扮演这个角色,它实现了iterator 方法。
不管实现如何变化,都可以使用 Iterator
为什么一定要考虑使用这种复杂的设计模式呢,如果是数组,直接用循环语句遍历处理不是更方便吗。一个很重要的方面就是这样可以将遍历与具体的实现分开,在上面的代码中,遍历书籍的时候,我们并没有调用书架(BookShelf)的方法,也就是说,while循环并没有依赖于书架(BookShelf)的实现,如果现在需要用其他容器的例如箱子(ArrayList)来装书,那么只要箱子(ArrayList)的iterator方法可以正确的返回Iterator实例,就算不对while循环做任何处理,代码也可以正常工作,这在代码的维护工作中是非常重要的。
设计模式的作用就是帮助我们编写可复用的代码,所谓可复用,就是指将类实现作为组件,当一个组件发生改变时,不需要对其他的组件进行修改或是只需要很小的修改即可应对。
注:参考自图解设计模式