Iterator 模式
本系列的文章主要是记录设计模式的学习过程,围绕《图解设计模式》和我自身对于设计模式的理解。在文章中出现的代码多为《图解设计模式》这本书中的代码。书中一共包含23个设计模式,这篇文章作为这个系列的第一篇文章。由于《图解设计模式》这本书内容十分简单,非常适合入门,如果对于设计模式想要进一步地研究,可以参阅一些其他书籍。
Iterator
模式是一种非常简单的设计模式,其设计出来的目的就是在不知道类具体内部实现的前提下,对这个类的集合中的元素进行一个一个的访问。当我们对集合对象增加一种新迭代或者存储方式的时候,并不需要修改对该集合对象访问的代码,只需要增加对应的迭代器即可。
接下来,我们通过书中的一个例子来简单的看一下什么是迭代器模式:
首先,我们声明一个Book
类,这个类存储书的一些信息:
public class Book {
private String bookName;
public Book(String bookName) {
this.bookName = bookName;
}
public String getBookName() {
return bookName;
}
@Override
public String toString() {
return "本书名称叫 " + this.getBookName();
}
}
接下来,我们声明一个接口Aggregate.java
,这个接口内部有一个函数,该返回一个迭代器。实现该接口表示将该类声明为可以遍历的集合,并可以获得遍历该类的迭代器。
import java.util.Iterator;
public interface Aggregate {
Iterator iterator();
}
我们有一个BookShelf
类,并实现上述的接口。其意义为一个书架可以被遍历,并且我们能够返回遍历的迭代器
import java.util.Iterator;
import java.util.List;
public class BookShelf implements Aggregate {
private Book [] books;
private int last;
public BookShelf(int shelfSize){
this.books = new Book[shelfSize];
this.last = 0;
}
public void appendBook(Book book){
this.books[last] = book;
last++;
}
public Book getBookAt(int i ){
return books[i];
}
public int getLength(){
return last;
}
@Override
public Iterator iterator() {
return new BookShelfIterator(this);
}
}
注意到,在最后的iterator()
函数中,我们返回了一个BookShelfIterator
,也就是说,我们按照这个迭代器中实现的方式进行遍历BookShelf
BookShelfIterator
import java.util.Iterator;
public class BookShelfIterator implements Iterator {
private BookShelf bookShelf;
private int cursor;
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
}
@Override
public Object next() {
Book book = bookShelf.getBookAt(cursor);
cursor++;
return book;
}
@Override
public boolean hasNext() {
return cursor<bookShelf.getLength();
}
}
Main.java
对集合进行遍历
import java.util.Iterator;
public class Main {
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf(5);
bookShelf.appendBook(new Book("哈利波特"));
bookShelf.appendBook(new Book("设计模式"));
bookShelf.appendBook(new Book("故事会"));
bookShelf.appendBook(new Book("情感分析"));
Iterator iterator = bookShelf.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
当我们的BookShelf
存储形式更改,或者我们的遍历的顺序更改时,我们不需要修改集合遍历这部分代码,只需要增加对应的迭代器即可。
上面这段代码和《图解设计模式》中的代码几乎一样,我在某些细节地方做了修改。同时,在BookShelf
中,我是用的是普通数组进行存储的,而没有使用ArrayList
等容器,是为了让大家更清晰的看到迭代器模式的工作方式。
一个迭代器模式的类图如下所示:
-
Aggregate(集合)
该角色负责定义创建
Iterator
角色的接口 -
ConcreteAggregate(具体的集合)
负责实现
Aggregate
角色所定义的接口。在这个例子中,由BookShelf
扮演,他实现了iterator()
的方法,并返回第一个访问该集合的迭代器 -
Iterator(迭代器)
Iterator
主要负责定义按顺序遍历元素的接口API,例如next()
和hasNext()
等方法 -
ConcreteIterator(具体的迭代器)
实现
Iterator
角色所定义的接口,实现具体的next()
和hasNext()
方法
应用了迭代器设计模式的好处就是,我们不需要知道集合存储元素的方式,即可对集合进行遍历。如果以后集合BookShelf
中存储的数组改为ArrayList
或者其他的容器类型,我们只需要添加一种新的对应这种存储方式的迭代器实现即可。