Iterator模式也叫迭代模式,是由GoF提出的23种设计模式的一种。Iterator模式是行为模式之一,它把对容器中包含的内部对象的访问委让给外部类,使用Iterator(遍历)按顺序进行遍历访问的设计模式。
本文介绍设计模式中的迭代(Iterator)模式的概念,用法,以及实际应用中怎么样使用迭代模式进行开发。

IBookList list = ...;
BookListIterator it = list.iterator();
while(it.hasNext()){
    Book book = it.next();
    ...
}
Iterator模式的概念
Iterator模式指对容器中包含的内部对象的访问委让给外部类,使用Iterator(遍历)按顺序进行遍历访问的设计模式。
在 程序设计中,经常有这种情况,需要从大量得数据(对象)集合中一个个地取出数据加以处理。Iterator模式就是为了有效地处理按顺序进行遍历访问的一 种设计模式,简单地说,Iterator模式提供一种有效的方法,可以屏蔽聚集对象集合的容器类的实现细节,而能对容器内包含的对象元素按顺序进行有效的 遍历访问。
所以,Iterator模式的应用场景可以归纳为满足以下几个条件:
- 访问容器中包含的内部对象
- 按顺序访问
为什么需要Iterator模式
在应用Iterator模式之前,首先应该明白Iterator模式用来解决什么问题。或者说,如果不使用Iterator模式,会存在什么问题。

我们举例来说明Iterator模式到底好在哪。

比如有一个Book类,一个管理Book的容器类BookList:

public class Book {
    ...
}
public class BookList {
    //保存Book对象数据
    private List bookList = new ArrayList();
    //添加Book对象至BookList容器
    public void addBook(Book book) {
        ...
    }
    //从BookList容器删除Book对象
    public void deleteBook(Book book) {
        ...
    }
    //其他方法
    ...
}

我们需要按顺序遍历访问BookList包含的Book对象。
怎么实现顺序遍历方法呢?
你可能会考虑以下这些遍历方法:

方法1,由容器自己实现顺序遍历。直接在BookList里添加顺序遍历方法:

public class BookList {
    private int index;
    ...
    //得到当前Book
    public Book getCurrentBook() {
        ...
        Book book = (Book)bookList.get(index);
        ...
        return book;
    }
    //是否存在下一个Book
    public boolean hasNext() {
        ...
    }
}

使用时,可能的使用方法是:

BookList bookList = ...;
...
while (bookList.hasNext()) {
    Book book = bookList.getCurrentBook();
    //对Book加以处理(略)
    ...
}

方法2,让调用者自己实现遍历。直接暴露BookList数据细节给外部,比如:

public class BookList {
    ...
    public List <Book> getBookList() {
        ...
        return bookList;
    }
}

可能的使用方法为:

BookList bookList = ...;
List <Book>bookDataList = bookList.getBookList();
...
for (int i=0; bookDataList != null && i<bookDataList.size(); i++) {
    Book book = bookDataList.get(i);
    //对Book加以处理(略)
    ...
}

以上方法1与方法2都可以实现对BookList所包含的Book对象进行遍历,这样有问题呢?
确实使用上没有任何问题。
但实现方法1中,
1,容器类BookList承担了太多功能:一方面需要提供添加删除等BookList本身应有的功能;一方面还需要提供遍历访问功能。
2,往往容器在实现遍历的过程中,需要保存遍历状态,当跟元素的添加删除等功能夹杂在一起,很容易引起混乱和程序运行错误等。

在实现方法2中,
容器本身未实现任何遍历方法,把这个遍历的任务交给了调用者,这样一来,暴露了容器本身的实现细节,如果一旦容器内部的数据接口发生变化,比如由于某种原 因,BookList的List bookList用Map bookList来实现,这样,所有调用方的程序不得不随着BookList的修改而修改。

Iterator模式很好地解决了以上问题。
我们先从JDK中的Collection Framework对Iterator模式的实现方法来说明Iterator模式。

Java Collection Framework对迭代模式的经典实现

1、Iterable.java


public interface Iterable<T> {
    Iterator<T> iterator();
}


2、迭代接口:Iterator接口,定义了遍历接口:


public interface Iterator<E> {
    boolean hasNext();
    E next();
    void remove();
}


3,容器接口:Collection接口,定义了iterator()方法,把遍历委让给Iterator的实现类。


public interface Collection<E> extends Iterable<E> {
    ......
    Iterator<E> iterator();
    ......
}


4、容器接口Collection的实现类与迭代接口Iterator的实现类:


public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    protected AbstractList() {
    }
    ......
    public Iterator<E> iterator() {
        return new Itr();
    }
    private class Itr implements Iterator<E> {     
        int lastRet = -1;
        int expectedModCount = modCount;
        public boolean hasNext() {
            return cursor != size();
        }
        public E next() {
            checkForComodification();
            try {
                int i = cursor;
                E next = get(i);
                lastRet = i;
                cursor = i + 1;
                return next;
            } catch (IndexOutOfBoundsException e) {
                checkForComodification();
                throw new NoSuchElementException();
            }
        }
        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();
            try {
                AbstractList.this.remove(lastRet);
                if (lastRet < cursor)
                    cursor--;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException e) {
                throw new ConcurrentModificationException();
            }
        }
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }
    ......
}

以上说明了Java Collection Framework里的对Iterator模式的基本实现方法。

这也是Iterator模式一种经典的实现方案。

经典的Iterator模式实现方案
下面是一种比较经典的Iterator模式实现方案,该实现方案基于接口设计原则,设计了以下几个接口或类:
迭代器接口Iterator :该接口必须定义实现迭代功能的最小定义方法集比如提供hasNext()和next()方法。
迭代器实现类 :迭代器接口Iterator的实现类。可以根据具体情况加以实现。
容器接口 :定义基本功能以及提供类似Iterator iterator()的方法。
容器实现类 :容器接口的实现类。必须实现Iterator iterator()方法。

Iterator模式的类图:

231054414.png


应用我们的上面介绍的例子,我们需要定义以下几个接口与类:

public class public interface IBookList {
    public BookListIterator iterator();
}
BookListImpl implements IBookList {
    public BookListIterator iterator() {
        return new BookListIteratorImpl(this);
    }
}
public interface BookListIterator {
    public boolean hasNext();
    public Book next();
}
public class BookListIteratorImpl implements BookListIterator {
    ...(具体实现过程略)
}


对容器的遍历方法例:


IBookList list = ...;
BookListIterator it = list.iterator();
while(it.hasNext()){
    Book book = it.next();
    ...
}


Iterator模式的优点
1,实现功能分离,简化容器接口。让容器只实现本身的基本功能,把迭代功能委让给外部类实现,符合类的设计原则。
2,隐藏容器的实现细节。
3,为容器或其子容器提供了一个统一接口,一方面方便调用;另一方面使得调用者不必关注迭代器的实现细节。
4,可以为容器或其子容器实现不同的迭代方法或多个迭代方法。