意圖(Intent)#
提供一種方法,在不暴露聚合物件內部表示的前提下,循序存取其元素。
別名(Also Known As)#
Cursor
動機(Motivation)#
聚合物件(如 List)應提供存取元素的方式,但不應暴露內部結構。此外,你可能需要以不同方式遍歷同一個聚合物件,甚至同時進行多個遍歷——但不希望為此而膨脹聚合物件的介面。
Iterator 模式的做法是將存取與遍歷的責任從聚合物件中抽離,放入獨立的 iterator 物件。Iterator 定義了存取元素的介面(First、Next、IsDone、CurrentItem),並追蹤當前位置。
為了支援多型迭代(polymorphic iteration)——在不知道具體聚合類別的情況下遍歷——可定義抽象的 AbstractList 和 Iterator,讓具體的 List 與 SkipList 各自提供對應的 Iterator 子類別。聚合物件透過 Factory Method(CreateIterator)來建立對應的 iterator,讓客戶端程式碼獨立於具體的聚合實作。
Iterator 模式的核心是分離遍歷機制與聚合物件。聚合物件負責儲存資料,Iterator 負責遍歷邏輯,兩者各司其職。
適用場景(Applicability)#
- 存取聚合物件的內容而不暴露其內部表示
- 支援對聚合物件的多種遍歷方式
- 提供統一的介面來遍歷不同的聚合結構(多型迭代)
結構(Structure)#
Aggregate 定義建立 Iterator 的介面。ConcreteAggregate 實作該介面,回傳對應的 ConcreteIterator。Iterator 定義存取與遍歷元素的介面。ConcreteIterator 實作 Iterator 介面並追蹤聚合中的當前位置。
classDiagram
class Aggregate {
<<interface>>
+CreateIterator()
}
class ConcreteAggregate {
+CreateIterator()
}
class Iterator {
<<interface>>
+First()
+Next()
+IsDone()
+CurrentItem()
}
class ConcreteIterator {
+First()
+Next()
+IsDone()
+CurrentItem()
}
Aggregate <|.. ConcreteAggregate
Iterator <|.. ConcreteIterator
ConcreteAggregate ..> ConcreteIterator : creates
ConcreteIterator --> ConcreteAggregate參與者(Participants)#
| 參與者 | 範例 | 職責 |
|---|---|---|
| Iterator | - | 定義存取與遍歷元素的介面 |
| ConcreteIterator | - | 實作 Iterator 介面;追蹤遍歷中的當前位置 |
| Aggregate | - | 定義建立 Iterator 物件的介面 |
| ConcreteAggregate | - | 實作建立對應 ConcreteIterator 的介面 |
協作方式(Collaborations)#
- ConcreteIterator 追蹤聚合中的當前物件,並能計算出下一個物件
優缺點(Consequences)#
- 支援多樣的遍歷策略——只需替換不同的 Iterator 實例即可改變遍歷演算法,也可透過子類別支援新的遍歷方式
- 簡化 Aggregate 介面——遍歷相關的介面由 Iterator 承擔,Aggregate 的介面更精簡
- 支援同時多個遍歷——每個 Iterator 維護自己的遍歷狀態,可在同一個聚合上同時進行多個遍歷
實作要點(Implementation)#
- 外部 vs. 內部迭代器
- External iterator:由客戶端控制迭代,顯式推進與取值——更彈性,例如可比較兩個集合
- Internal iterator:由 iterator 控制迭代,客戶端提供要執行的操作——更易用,但在缺乏 closure 的語言(如 C++)中較受限
- 遍歷演算法的歸屬
- 放在 Iterator 中:容易在同一聚合上套用不同演算法,也利於跨聚合複用
- 放在 Aggregate 中,Iterator 僅作為 cursor 儲存狀態:但可能需要存取聚合的私有成員
- Robust iterator——在遍歷過程中修改聚合可能導致元素被跳過或重複存取。穩健的 iterator 透過向聚合註冊來獲知插入或刪除事件,自動調整內部狀態
- 額外操作——除基本的
First、Next、IsDone、CurrentItem外,可提供Previous(雙向遍歷)或SkipTo(跳至符合條件的元素) - 多型 Iterator 的代價——需透過 factory method 動態配置,客戶端負責刪除。可使用 stack-allocated 的 Proxy 來自動清理(C++ 的 RAII 技巧)
對於 Composite 結構的遍歷,external iterator 需維護路徑堆疊來追蹤位置,實作較複雜。此時使用 internal iterator 可利用遞迴呼叫堆疊隱式記錄路徑,通常更簡潔。
- Iterator 的特權存取——Iterator 可作為 Aggregate 的
friend,以高效存取內部結構。為避免新增遍歷時需修改 Aggregate,可在 Iterator 基底類別中定義protected操作供子類別使用 - NullIterator——一個退化的 iterator,其
IsDone永遠回傳 true。在遍歷樹狀結構時,葉節點回傳 NullIterator,使整體遍歷邏輯統一
已知應用(Known Uses)#
- Booch Components 為有界(bounded)與無界(unbounded)Queue 提供基於抽象 Queue 介面的 iterator
- Smalltalk 標準集合類別提供內部 iterator 方法
do:,接受 block(closure)作為參數 - ET++ 提供多型 iterator 與清理用的 Proxy
- Unidraw 使用 cursor-based iterator
- ObjectWindows 2.0 透過重載
++運算子實現迭代語法
相關模式(Related Patterns)#
- Composite:Iterator 常被應用於遞迴結構如 Composite
- Factory Method:多型 iterator 依賴 factory method 來建立適當的 Iterator 子類別
- Memento:可與 Iterator 搭配使用,用 memento 捕捉迭代狀態