意圖(Intent)#

提供一種方法,在不暴露聚合物件內部表示的前提下,循序存取其元素。

別名(Also Known As)#

Cursor

動機(Motivation)#

聚合物件(如 List)應提供存取元素的方式,但不應暴露內部結構。此外,你可能需要以不同方式遍歷同一個聚合物件,甚至同時進行多個遍歷——但不希望為此而膨脹聚合物件的介面。

Iterator 模式的做法是將存取與遍歷的責任從聚合物件中抽離,放入獨立的 iterator 物件。Iterator 定義了存取元素的介面(FirstNextIsDoneCurrentItem),並追蹤當前位置。

為了支援多型迭代(polymorphic iteration)——在不知道具體聚合類別的情況下遍歷——可定義抽象的 AbstractListIterator,讓具體的 List 與 SkipList 各自提供對應的 Iterator 子類別。聚合物件透過 Factory MethodCreateIterator)來建立對應的 iterator,讓客戶端程式碼獨立於具體的聚合實作。

Iterator 模式的核心是分離遍歷機制與聚合物件。聚合物件負責儲存資料,Iterator 負責遍歷邏輯,兩者各司其職。

適用場景(Applicability)#

  • 存取聚合物件的內容而不暴露其內部表示
  • 支援對聚合物件的多種遍歷方式
  • 提供統一的介面來遍歷不同的聚合結構(多型迭代)

結構(Structure)#

Aggregate 定義建立 Iterator 的介面。ConcreteAggregate 實作該介面,回傳對應的 ConcreteIteratorIterator 定義存取與遍歷元素的介面。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 透過向聚合註冊來獲知插入或刪除事件,自動調整內部狀態
  • 額外操作——除基本的 FirstNextIsDoneCurrentItem 外,可提供 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 捕捉迭代狀態