問題背景
你有一個資料集合(陣列、鏈結串列、樹、圖),使用者想要逐一遍歷裡面的元素。如果把遍歷的邏輯暴露給外部(「你要自己知道陣列要用 index,鏈結串列要用 next 指針,樹要用遞迴」),使用者的程式碼就跟集合的內部結構緊密耦合——換一種集合結構就要改所有遍歷的程式碼。
Iterator Pattern 把「怎麼遍歷」封裝成一個獨立的 Iterator 物件,讓使用者只需要問「有沒有下一個」和「給我下一個」,不需要知道背後是什麼資料結構。
結構
Collection(Iterable)
└── createIterator() → Iterator
Iterator
├── hasNext(): boolean
└── next(): Element
Java 實作
// Iterator 介面(Java 標準庫已有)
// java.util.Iterator<T>
// 自定義範圍集合
class Range implements Iterable<Integer> {
private final int start, end;
Range(int start, int end) {
this.start = start;
this.end = end;
}
@Override
public Iterator<Integer> iterator() {
return new Iterator<>() {
private int current = start;
@Override
public boolean hasNext() {
return current < end;
}
@Override
public Integer next() {
return current++;
}
};
}
}
// 使用:for-each 語法糖就是 Iterator 的包裝
for (int n : new Range(1, 5)) {
System.out.println(n); // 1 2 3 4
}JavaScript / TypeScript
// JavaScript 用 Symbol.iterator 實作 iterable protocol
class InfiniteSequence {
constructor(private start: number) {}
[Symbol.iterator]() {
let current = this.start;
return {
next: () => ({
value: current++,
done: false
})
};
}
}
// for...of 透過 Symbol.iterator 工作
for (const n of new InfiniteSequence(1)) {
if (n > 5) break;
console.log(n); // 1 2 3 4 5
}
// Generator function 是 Iterator 的語法糖
function* range(start: number, end: number) {
for (let i = start; i < end; i++) yield i;
}Python
class Range:
def __init__(self, start, end):
self.start = start
self.end = end
def __iter__(self):
return RangeIterator(self.start, self.end)
class RangeIterator:
def __init__(self, start, end):
self.current = start
self.end = end
def __next__(self):
if self.current >= self.end:
raise StopIteration
val = self.current
self.current += 1
return val
# Python 內建 range() 就是這個 pattern 的實作
for n in Range(1, 5):
print(n) # 1 2 3 4實際應用
- 資料庫結果集:Cursor-based pagination——每次
next()拉下一頁,不需要一次載入全部 - 檔案讀取:逐行讀取大檔案,不把整個檔案載入記憶體
- Graph / Tree 遍歷:把 BFS 或 DFS 的遍歷邏輯封裝成 Iterator,使用者寫
for node in graph.bfs(): - Lazy evaluation:Generator 讓 Iterator 支援無限序列,只在需要時計算下一個值