配列などの要素を1つ1つ数え上げるときに使用する。
配列aryの要素を全て表示するには、for文を使って以下のように表現できる
$ary_length = count(ary); for ($i = 0; i < $arr_length - 1; $i++) { print $ary[$i]; }
ここで使われている変数iの働きを抽象化して、一般化したものを
Iteratorパターンという
「本棚(BookShelf?)の中に本(Book)を入れ、その本の名前を順番に表示する」
プログラムを考えてみる
<?php interface Aggregate { function iterator_method(); } ?>
<?php interface IteratorClass { function hasNext(); function next(); } ?>
<?php class Book { private $book_name; public function __construct($input_book_name) { $this->book_name = $input_book_name; } public function getName() { return $this->book_name; } } ?>
<?php require_once("Aggregate.class.php"); require_once("BookShelfIterator.class.php"); class BookShelf implements Aggregate { private $books; private $last; public function __construct($maxsize) { $this->books = array_pad(array(), $maxsize, 0); $this->last = 0; } public function getBookAt($index) { return $this->books[$index]; } public function appendBook($book) { $this->books[$this->last] = $book; $this->last++; } public function getLength() { return $this->last; } public function iterator_method() { return new BookShelfIterator($this); } } ?>
<?php require_once("IteratorClass.class.php"); class BookShelfIterator implements IteratorClass{ private $book_shelf_iterator; private $index; public function __construct($book_shelf) { $this->book_shelf_iterator = $book_shelf; $this->index = 0; } public function hasNext() { if ($this->index < $this->book_shelf_iterator->getLength()) { return true; } else { return false; } } public function next() { $book = $this->book_shelf_iterator->getBookAt($this->index); $this->index++; return $book; } } ?>
<?php require_once("BookShelf.class.php"); require_once("Book.class.php"); class Main { public function __construct() { $book_shelf = new BookShelf(4); $book_shelf->appendBook(new Book("Around the World in 80 Days")); $book_shelf->appendBook(new Book("Bible")); $book_shelf->appendBook(new Book("Cinderella")); $book_shelf->appendBook(new Book("Daddy-Long-Legs")); $book_shelf_iterator = $book_shelf->iterator_method(); while ($book_shelf_iterator->hasNext()) { $book = $book_shelf_iterator->next(); echo $book->getName()."<br />"; } } } new Main(); ?>
要素を順番に数え上げていく役。
サンプルプログラムではIteratorClass?クラスにあたる。
Iterator役が指定したものを、実際に実装する役。
この役はスキャンするために必要な情報を持っている必要がある。
サンプルプログラムではBookShelfIterator?クラスにあたる。
Iterator役を作り出すものを定めてくれる役。
サンプルプログラムではAggregateインターフェイスにあたる。
Aggregate役が定めたものを実際に実装する役。
具体的なIterator役、つまりConcreteIterator?役のインスタンスを作り出す。
サンプルプログラムではBookShelf?:qクラスにあたる。
while (it.hasNext) { Book book = (Book)it.next(); System.out.println(book.getName()); }
ここで使っているのは、hasNextとnextというIteratorのメソッドだけ。
BookShelf?の実装で使われているメソッドは使用していない。
つまり、このwhileループは、BookShelf?の実装には依存しない。
BookShelf?を実装した人が、配列を使って本を管理することをやめて、
別の方法で管理したとしても、
BookShelf?がiteratorメソッドを持っていて、
正しいIteratorを返してくれれば、
(つまり、hasNextとnextメソッドが正しく実装されているクラスのインスタンスを返してくれれば)
上記のwhileループはまったく変更しなくても動作する。
Iteratorは集合体から1つずつ要素を取り出して数え上げていく。
数え上げていくには、要素に対してなんらかの処理が必要だが、
Iteratorのインターフェイスの中にはその処理は記述されていない。
Visitorはたくさんの要素が集まっている中を歩きわたりながら、
同じ処理を繰り返し適用していくというもの。
数えながら、同時に定型処理を行っていく。
そのときに、IteratorとVisitorを使う。
iteratorメソッドがIteratorのインスタンスを作成するときに、
Factory Methodパターンが使われる場合がある
参考資料