The Iterator Pattern provides a way to access elements of a collection sequentially without exposing its underlying representation. It separates traversal logic from collection implementation.
- Decoupling: Separates collection and traversal.
- Simplified Interface: Provides a clear way to iterate.
- Single Responsibility Principle: Collection maintains storage; iterator manages traversal.
- You want uniform iteration over different collections.
- You need to encapsulate traversal logic.
interface Iterator<T> {
next(): T | null;
hasNext(): boolean;
}
interface Aggregate<T> {
getIterator(): Iterator<T>;
}
class NumberCollection implements Aggregate<number> {
private numbers: number[] = [];
addNumber(num: number): void {
this.numbers.push(num);
}
getIterator(): Iterator<number> {
return new NumberIterator(this.numbers);
}
}
class NumberIterator implements Iterator<number> {
private index: number = 0;
private numbers: number[];
constructor(numbers: number[]) {
this.numbers = numbers;
}
next(): number | null {
if (this.hasNext()) {
return this.numbers[this.index++];
}
return null;
}
hasNext(): boolean {
return this.index < this.numbers.length;
}
}
const numbers = new NumberCollection();
numbers.addNumber(1);
numbers.addNumber(2);
numbers.addNumber(3);
const iterator = numbers.getIterator();
while (iterator.hasNext()) {
console.log(iterator.next());
}
1
2
3
The Iterator Pattern provides a clean and efficient way to traverse collections without exposing their internal structures, improving modularity and maintainability.