迭代器模式是一種使用頻率非常高的設計模式,迭代器用于對一個聚合物件進行遍歷,通過引入迭代器可以將資料的遍歷功能從聚合物件中分離出來,聚合物件只負責存盤資料,聚合物件只負責存盤資料,而遍歷資料由迭代器來完成,
模式動機
一個聚合物件,如一個串列(List)或者一個集合(Set),應該提供一種方法來讓別人可以訪問它的元素,而又不需要暴露它的內部結構,此外,針對不同的需要,可能還要以不同方式遍歷整個聚合物件,但是我們不希在聚合物件的抽象層介面中充斥著各種不同遍歷的操作,怎樣遍歷一個聚合物件,又不需要了解聚合物件的內部結構,還能提供多種不同的遍歷方式,這就是迭代器模式所要解決的問題,
迭代器模式中,提供一個外部的迭代器來對聚合物件進行訪問和遍歷,迭代器定義一個訪問該聚合元素的介面,并且可以跟蹤當前遍歷物件,了解哪些元素已經遍歷過而哪些沒有,
模式定義
提供一種方法來訪問聚合物件,而不用暴露這個物件的內部表示,其別名為游標(Cursor),迭代器模式是一種物件行為模式,
模式結構

-
Iterator(抽象迭代器)
抽象迭代器定義了訪問和遍歷元素的介面,一般宣告以下方法:
- 用于獲取第一個元素的 first()
- 用于訪問下一個元素的 next()
- 用于判斷是否還有下一個元素的 hasNext()
- 用于獲取當前元素的 currentItem()
-
ConcreteIterator(具體迭代器)
具體迭代器實作了抽象迭代器介面,完成對聚合物件的遍歷,同時在對聚合進行遍歷時跟蹤其當前位置
-
Aggregate(抽象聚合類)
抽象聚合類用于存盤物件,并定義創建相應迭代器物件的介面,宣告一個 createIterator() 方法用于創建一個迭代器物件
-
ConcreteAggregate(具體聚合類)
具體聚合類實作了創建相應迭代器的介面,實作了在聚合類中宣告的 createIterator() 方法,該方法回傳一個與具體聚合對應的具體迭代器 ConcreteIterator 實體
模式分析
存盤資料是聚合物件的最基本職責,其中包含存盤資料的型別、存盤空間的大小、存盤空間的分配,以及存盤的方式和順序,然而,聚合物件除了能存盤資料外,還必須提供遍歷訪問其內部資料的方式,同時這些遍歷方式可能會根據不同的情形提供不同的實作,
因此,聚合物件主要有兩個職責:一是存盤內部資料;二是遍歷內部資料,前者是聚合物件的基本功能,后者是可以分離的,根據單一職責原則,物件承擔的職責越少,物件的穩定性就越好,我們將遍歷聚合物件中資料的行為提取出來,封裝到一個迭代器中,通過專門的迭代器來遍歷聚合物件的內部資料,迭代器模式是單一職責原則的完美體現,
下面通過一個簡單的自定義迭代器來分析迭代器模式的結構
首先定義一個簡單的迭代器去介面
public interface MyIterator {
void first(); // 訪問第一個元素
void next(); // 訪問下一個元素
boolean isLast(); // 判斷是否是最后一個元素
Object currentItem(); // 獲取當前元素
}
然后需要定義一個聚合介面
public interface MyCollection {
// 回傳一個 MyIterator 迭代器物件
MyIterator createIterator();
}
定義好抽象層之后,我們需要定義抽象迭代器介面和抽象聚合介面的實作類,一般將具體迭代器類作為具體聚合類的內部類,從而迭代器可以實作直接訪問聚合類中的資料
public class NewCollection implements MyCollection {
private Object[] obj = {"dog", "pig", "cat", "monkey", "pig"};
public MyIterator createIterator() {
return new NewIterator();
}
private class NewIterator implements MyIterator {
private int currentIndex = 0;
public void first() {
currentIndex = 0;
}
public void next() {
if(currentIndex < obj.length) {
currentIndex++;
}
}
public boolean isLast() {
return currentIndex == obj.length;
}
public void currentItem() {
return obj[currentIndex];
}
}
}
NewCollection 類實作了 MyCollection 介面,實作了 createIterator() 方法,同時定義了一個陣列用于存盤資料元素,還定義了一個實作了 MyIterator 介面的內部類,索引變數 currentIndex 用于保存所操作的陣列元素的下標值,客戶端代碼如下:
public class Client {
public static void process(MyCollection collection) {
MyIterator i = collection.createIterator();
while(!i.isLast()) {
System.out.println(i.currentItem().toString());
i.next();
}
}
public static void main(String args[]) {
MyCollection collection = new NewCollection();
process(collection);
}
}
除了使用內部類實作之外,也可以使用常規的方式來實作迭代器
public class ConcreteIterator implements Iterator {
private ConcreteAggregate objects;
public ConcreteIterator(ConcreteAggregate objects) {
this.objects = objects;
}
public void first() {
...
}
public void next() {
...
}
public boolean isLast() {
...
}
public void currentItem() {
...
}
}
public class ConcreteAggregate implements Aggregate {
...
public Iterator createIterator() {
return new ConcreteIterator(this);
}
}
迭代器模式中應用了工廠方法模式,聚合類充當工廠類,而迭代器充當產品類
模式優缺點
迭代器模式優點:
- 支持以不同的方式遍歷一個聚合物件,在迭代器模式中只需要用一個不同的迭代器來替換原有迭代器即可改變遍歷演算法,也可以自己定義迭代器的子類以支持新的遍歷方式,
- 迭代器簡化了聚合類,原有聚合物件不再需要自行提供遍歷資料等操作方法,
- 在同一個聚合上可以有多個遍歷,由于每個迭代器都保持自己的遍歷狀態,因此可以對一個聚合物件進行多個遍歷操作,
- 增加新的聚合類和迭代器類都很方便,無須修改原代碼,滿足開閉原則,
迭代器模式缺點:
- 由于迭代器模式將存盤資料和遍歷資料的職責分離,增加新的聚合類需要對應增加新的迭代器類,類的個數成對增加,在一定程度上增加了系統的復雜性
模式適用環境
在以下情況可以使用迭代器模式:
- 訪問一個聚合物件的內容而無須暴露它的內部表示
- 需要為聚合物件提供多種遍歷方式
- 為遍歷不同的聚合結構提供一個統一的介面
Java 迭代器
Java 中的集合框架 Collections,其基本介面層次結構如圖

Collection 是所有集合類的根介面,它的主要方法如下:
boolean add(Object c);
boolean addAll(Collection c);
boolean remove(Object o);
boolean removeAll(Collection c);
boolean remainAll(Collection c);
Iterator iterator();
Collection 的 iterator() 方法回傳一個 java.util.Iterator 型別的物件,而其子介面 java.util.List 的 listIterator() 方法回傳一個 java.util.ListIterator 型別的物件,ListIterator 是 Iterator 的子類,它們構成了 Java 語言對迭代器模式的支持,
在 JDK 中,Iterator 介面具有如下三個基本方法:
- Object next():通過反復呼叫 next() 方法可以逐個訪問聚合中的元素
- boolean hasNext():用于判斷聚合物件在是否還存在下一個元素,為了不拋出例外,必須在呼叫 next() 之前先呼叫 hasNext(),如果迭代物件仍然擁有可供訪問的元素,那么 hasNext() 回傳 true
- void remove():洗掉上一次呼叫 next() 時回傳的元素
Java 迭代器可以理解為它作業時在聚合物件的各個元素之間,每呼叫一次 next() 方法,迭代器便越過下個元素,并且回傳它剛越過的那個元素的地址參考,

在第一個 next() 方法被呼叫時,迭代器由“元素1”與“元素2”之間移動至“元素2”與“元素3”之間,跨越了“元素2”,因此 next() 方法將回傳對“元素2”的參考;在第二個 next() 方法被呼叫時,迭代器由“元素2”與“元素3”之間移至“元素3”與“元素4”之間,next() 方法將回傳對“元素3”的參考,此時呼叫 remove() 方法,則可將”元素3“洗掉,
需要注意的是,next() 方法與 remove() 方法的呼叫是相互關聯的,如果呼叫 remove() 之前沒有先對 next() 進行呼叫,那么將拋出例外,因為沒有任何可供洗掉的元素
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/8584.html
標籤:設計模式
上一篇:【設計模式】牛掰格拉斯的代理模式
下一篇:設計模式的分類
