📝
# デザインパターンを学ぶ #23 イテレーター(Iterator)
1. はじめに
今回は Iterator(イテレーター)パターン。
目的は、集合体の要素へ順番にアクセスする仕組みを統一することです。
典型的な用途は、配列・リスト・ツリーなど、内部構造に依存せずに要素を順に取り出したいときです。
コレクションの種類が増えても「使う側のコードは同じ操作で済む」のが強みです。
2. Iteratorとは?
イテレーターは、コレクションの走査処理をオブジェクトに切り出したものです。
登場役は以下の2つが中心です:
-
Iterator … 要素を順に取り出すためのインターフェース(
hasNext(),next()など) - Aggregate(集合体) … 自分専用のイテレーターを返すメソッドを持つ
これにより「どのように走査するか(内部構造)」を隠蔽しつつ、共通の方法で扱えます。
3. 実装イメージ(PHP)
<?php
// Iterator インターフェース
interface IteratorInterface {
public function hasNext(): bool;
public function next();
}
// 集合体インターフェース
interface Aggregate {
public function createIterator(): IteratorInterface;
}
// 具体的な集合体(本棚)
class BookShelf implements Aggregate {
private array $books = [];
public function addBook(string $book): void {
$this->books[] = $book;
}
public function getBookAt(int $index): string {
return $this->books[$index];
}
public function count(): int {
return count($this->books);
}
public function createIterator(): IteratorInterface {
return new BookShelfIterator($this);
}
}
// 具体的なイテレーター
class BookShelfIterator implements IteratorInterface {
private BookShelf $bookShelf;
private int $index = 0;
public function __construct(BookShelf $bookShelf) {
$this->bookShelf = $bookShelf;
}
public function hasNext(): bool {
return $this->index < $this->bookShelf->count();
}
public function next(): string {
return $this->bookShelf->getBookAt($this->index++);
}
}
// --- 実行例 ---
$bookShelf = new BookShelf();
$bookShelf->addBook("Design Patterns");
$bookShelf->addBook("Refactoring");
$bookShelf->addBook("Clean Code");
$it = $bookShelf->createIterator();
while ($it->hasNext()) {
echo $it->next() . PHP_EOL;
}
// 出力:
// Design Patterns
// Refactoring
// Clean Code
4. メリット・デメリット
メリット
- コレクションの内部構造を隠蔽できる
- 配列・リスト・ツリーなど異なる構造でも同じ方法で走査できる
- 複数の走査方法(順方向・逆方向)を追加しやすい
デメリット
- 実装クラスが増える
- PHPの
foreachやIteratorAggregateが既に同様の仕組みを持つため、自作は冗長になることもある
5. 使いどころ
- 独自コレクションを実装するとき(例えばドメイン固有のリスト)
- 異なるデータ構造を同じ操作で扱いたいとき
- 走査処理を外に漏らしたくないとき
実際のPHP開発では SPL(Standard PHP Library)の Iterator や IteratorAggregate を使うことが多く、フレームワークのコレクション実装でもこのパターンが応用されています。
Discussion