設計模式:迭代器模式 (Iterator)
7 分鐘
Iterator 提供一種方式,依序存取集合中的每個元素,而不暴露它底層的結構。
意圖與用途
當一個集合的內部結構很複雜時 (樹、圖、排序後的結果、分頁資料),客戶端會希望用統一的方式走訪它,而不必知道底層究竟是走樹、走陣列,還是打 API。
Iterator 提供一致的遍歷介面,集合則把實作細節藏在後面。
結構與角色
- Iterator:遍歷的介面 (
next()、hasNext()) - Iterable:能產生 Iterator 的集合介面
- ConcreteIterator:實作遍歷邏輯
- ConcreteAggregate:實際的集合物件
實作範例:訂單集合遍歷
TypeScript
interface Iterator {
next(): T | undefined;
hasNext(): boolean;
}
interface Iterable {
createIterator(): Iterator;
}
// 訂單物件
interface Order {
id: string;
total: number;
status: 'pending' | 'shipped' | 'delivered';
}
// ConcreteAggregate:訂單集合
class OrderCollection implements Iterable {
private orders: Order[] = [];
add(order: Order): void {
this.orders.push(order);
}
createIterator(): Iterator {
return new OrderIterator(this.orders);
}
// 也可以提供篩選用的迭代器
createFilteredIterator(status: Order['status']): Iterator {
return new FilteredOrderIterator(this.orders, status);
}
}
// ConcreteIterator:依序遍歷
class OrderIterator implements Iterator {
private index = 0;
constructor(private orders: Order[]) {}
hasNext(): boolean { return this.index < this.orders.length; }
next(): Order | undefined { return this.orders[this.index++]; }
}
// ConcreteIterator:只走訪特定狀態
class FilteredOrderIterator implements Iterator {
private filtered: Order[];
private index = 0;
constructor(orders: Order[], status: Order['status']) {
this.filtered = orders.filter(o => o.status === status);
}
hasNext(): boolean { return this.index < this.filtered.length; }
next(): Order | undefined { return this.filtered[this.index++]; }
}
// 使用
const collection = new OrderCollection();
collection.add({ id: 'A001', total: 1200, status: 'pending' });
collection.add({ id: 'A002', total: 800, status: 'shipped' });
collection.add({ id: 'A003', total: 500, status: 'pending' });
const iterator = collection.createFilteredIterator('pending');
while (iterator.hasNext()) {
const order = iterator.next()!;
console.log(`訂單 ${order.id}: $${order.total}`);
} 適用情境
適用時機
- 需要用統一的方式走訪內部結構各異的集合
- 客戶端不需要知道、也不必在意集合內部是怎麼表示的
實務補充
JavaScript/TypeScript 本身就內建了迭代器協定 (Symbol.iterator),而 Generator 函式能讓你很簡潔地實作自訂迭代器。自訂迭代器常用於虛擬捲動、範圍走訪,以及分頁 API 的回應。
總結
Iterator 把集合的儲存邏輯與遍歷邏輯分了開來。客戶端只管消費一個 Iterator,不需要理解底層的資料結構。這個模式如此基礎,幾乎每一種現代語言的標準函式庫都內建了它。