迭代器模式定義
迭代器模式(Iterator),提供一種方法順序訪問(wèn)一個(gè)聚合對(duì)象中的各種元素,而又不暴露該對(duì)象的內(nèi)部表示。
Java程序員在使用集合(collection)時(shí),并不需要關(guān)注其類型是數(shù)組、列表、集合(set)還是其他,有些人并不知道這些集合包其實(shí)是使用了迭代器模式來(lái)實(shí)現(xiàn)的。
目的
迭代器模式提供了一種順序遍歷聚合對(duì)象元素而不暴露其內(nèi)部實(shí)現(xiàn)的方法。
實(shí)現(xiàn)
迭代器模式基于兩個(gè)抽象類或接口,可以通過(guò)成對(duì)的具體類來(lái)實(shí)現(xiàn)。

- Aggregate(抽象容器):應(yīng)該由所有類實(shí)現(xiàn)的抽象類,并且可以由迭代器遍歷。這對(duì)應(yīng)于java.util.Collection接口。
- Iterator(抽象迭代器):抽象迭代器是迭代器抽象類,它定義遍歷容器對(duì)象的操作以及返回對(duì)象的操作。
- ConcreteAggregate(具體容器):具體容器可以實(shí)現(xiàn)內(nèi)部不同的結(jié)構(gòu),但會(huì)暴露處理遍歷容器的具體迭代器。
- ConcreteIterator(具體迭代器):這是處理特定具體容器類的具體迭代器。實(shí)際上,對(duì)于每個(gè)具體容器,必須實(shí)現(xiàn)一個(gè)具體迭代器。
實(shí)例
將書(shū)(Book)放到書(shū)架(BookShelf)中,并將書(shū)名按順序顯示。
Aggregate 接口
所要遍歷的集合的接口。實(shí)現(xiàn)了該接口的類將成為一個(gè)可以保存多個(gè)元素的集合,類似數(shù)組。
Aggregate接口中聲明的方法為iterator,作用為生成一個(gè)用于遍歷的迭代器。
/**
* @author: Jay Mitter
* @date: 2020-08-23 20:54
* @description: 表示集合的接口
*/
public interface Aggregate<E> {
/**
* 返回迭代器
* @return iterator
*/
Iterator<E> iterator();
}
Iterator 接口
作用為遍歷集合中元素,相當(dāng)于循環(huán)語(yǔ)句中的循環(huán)變量(for(int i =0;i<arr.lenth;i++),具體實(shí)現(xiàn)一個(gè)順序遍歷的迭代器。
hasNext()方法判斷是否存在下一個(gè);
next()方法獲取下一個(gè)元素。特殊說(shuō)明下,next()方法在獲取元素的同時(shí),要將計(jì)數(shù)器向下一個(gè)元素的計(jì)數(shù)加一。獲取的是當(dāng)前元素,并指向下一個(gè)元素。
/**
* @author: Jay Mitter
* @date: 2020-08-23 20:54
* @description: 遍歷集合的接口
*/
public interface Iterator<E> {
/**
* 是否有下一個(gè)元素
* @return true false
*/
boolean hasNext();
/**
* 獲取的是當(dāng)前元素,并將計(jì)數(shù)器向下一個(gè)元素的計(jì)數(shù)加一,指向下一個(gè)元素
* @return E
*/
E next();
}
BookShelf 類
書(shū)架類,作為存放書(shū)的集合類,實(shí)現(xiàn)Aggregate接口。實(shí)現(xiàn)了Aggregate接口的iterator方法。
主要點(diǎn)在iterator()方法,方法返回了遍歷書(shū)架時(shí)要用的BookShelfIterator類作為書(shū)架的迭代器。當(dāng)外部要遍歷書(shū)架時(shí)會(huì)調(diào)用該方法。
/**
* @author: Jay Mitter
* @date: 2020-08-25 22:27
* @description: 表示書(shū)架的類
*/
public class BookShelf implements Aggregate<Book> {
private List<Book> bookList;
public BookShelf() {
this.bookList = new ArrayList<>();
}
@Override
public Iterator<Book> iterator() {
return new BookShelfIterator(this);
}
public Book getBookAt(int index) {
return this.bookList.get(index);
}
public void appendBook(Book book) {
this.bookList.add(book);
}
public int getLength() {
return bookList.size();
}
}
BookShelfIterator 類
作為一個(gè)迭代器,要實(shí)現(xiàn)Iterator接口。index為迭代器當(dāng)前所指向的下標(biāo)。hasNext判斷還有沒(méi)有下一本。通過(guò)下標(biāo)和總數(shù)比較判斷。next獲取當(dāng)前書(shū),并指向下一個(gè)。
/**
* @author: Jay Mitter
* @date: 2020-08-25 22:30
* @description: 遍歷書(shū)架的類
*/
public class BookShelfIterator implements Iterator<Book> {
private BookShelf bookShelf;
private int index;
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
this.index = 0;
}
@Override
public boolean hasNext() {
if (index < bookShelf.getLength()) {
return true;
} else {
return false;
}
}
@Override
public Book next() {
Book book = bookShelf.getBookAt(index);
index++;
return book;
}
}
測(cè)試:
/**
* 行為型模式——迭代器模式
*/
@Test
public void testBehaviorIterator() {
BookShelf bookShelf = new BookShelf();
bookShelf.appendBook(new Book("Around the World in 80 Days"));
bookShelf.appendBook(new Book("Bible"));
bookShelf.appendBook(new Book("Cinderella"));
bookShelf.appendBook(new Book("Daddy-Long-Legs"));
Iterator<Book> it = bookShelf.iterator();
while (it.hasNext()) {
Book book = it.next();
System.out.println(book.getName());
}
}
為什么使用迭代器模式
如果是數(shù)組,直接使用for玄幻語(yǔ)句進(jìn)行遍歷處理不就可以了嗎?
為什么要在集合之外引入Iterator角色?
一個(gè)重要的理由:引入Iterator后可以將遍歷與實(shí)現(xiàn)分離開(kāi)來(lái)。
while (it.hasNext()) {
Book book = it.next();
System.out.println(book.getName());
}
這里使用了Iterator的hasNext方法和next方法,并沒(méi)有調(diào)用BookShelf的方法。也就是說(shuō),這里的while循環(huán)并不依賴于BookShelf的實(shí)現(xiàn)。
例如在BookShelf的開(kāi)發(fā)人員決定放棄用數(shù)組來(lái)管理書(shū)本,而是java.util.Vector取而代之,會(huì)怎么樣呢。不管BookShelf如何變化,只要BookShelf的iterator方法能正確的返回Iterator的實(shí)例,即使不對(duì)上面的while循環(huán)做任何修改,代碼都可以正常工作。
對(duì)于BookShelf的調(diào)用者來(lái)說(shuō)真的太方便了,設(shè)計(jì)模式的作用就是幫助我們編寫(xiě)可復(fù)用的類。
所謂可復(fù)用,就是指將類實(shí)現(xiàn)為組件,當(dāng)一個(gè)組件發(fā)生改變時(shí),不需要對(duì)其他組件進(jìn)行修改或是只需要很小的修改即可應(yīng)對(duì)。這也就能理解為什么在示例程序中iterator方法返回值不是BookShelf類而是iterator類型了。這表明,程序就是要使用iterator的方法進(jìn)行編程而不是bookshelfiterator的方法。
在Java現(xiàn)有版本中的java.util.Iterator<E>類和java.util.Collection<E>類,是實(shí)現(xiàn)新容器和迭代器很好的例子。當(dāng)需要具有特定行為的容器時(shí),我們應(yīng)該考慮擴(kuò)展java.collection包中實(shí)現(xiàn)的一個(gè)類,而不是創(chuàng)建一個(gè)新類。