今回は、ご存知デザパタの
第1章 Iterator 〜1つ1つ数えあげる〜
について自分なりにまとめたいと思います。
イテレーター(iterator)とは
何かの集合体を、数える人
→ 何かの集合体(=aggregate)つまり数える対象が必要
→ 何かの集合体(=aggregate)がいてこその役に立つ
参考:
PHPで書き換えてくれてるソース
https://github.com/HappyDays-jQuery/GoF/tree/master/src/Iterator
※PHPでは組み込みで複数のインターフェースがあるので便利!
– Iteratorインターフェース
– IteratorAggregateインターフェース ..など
何かの集合体(aggregate)と、それを数える人(iterator)を別クラスにすることで、
役割分担ができ、疎結合になる。
→ ただし、aggregateとiteratorを別にする必要がない場合は、
両方の役割をもつIteratorAggregateを使うこともできる。
こんな感じ
全体コード→https://github.com/kin29/DezaPata/pull/2/files
– Bookクラス
– BookShelfクラス(=aggregate)
– BookShelfIteratorクラス(=iterator)
– コンテキスト(使う側)
BookShelf(集合体)の中にBook(要素)があり、
BookShelfIteratorが本を一つ一つ数えていく感じです。
BookShelfクラス
<?php /** * 何か(=本)の集合体[Aggregate] */ class BookShelf { .... public function getIterator(): BookShelfIterator { return new BookShelfIterator($this); } }
コンテキスト(使う側)
<?php $bookShelf = new BookShelf(); $bookShelf->appendBook(new Book('星の王子様')); $bookShelf->appendBook(new Book('かいけつゾロリ')); $bookShelf->appendBook(new Book('ミッケ!')); $bookShelfIt = $bookShelf->getIterator(); while ($bookShelfIt->hasNext()) { echo $bookShelfIt->next()->getName() . "\n"; }
実行すると、appendした本の名前が入れた順番に1つずつ表示されます。
$ php contextIterator.php 星の王子様 かいけつゾロリ ミッケ!
イテレータのいいところ
何かの集合体(=aggregate)や数え方(=iterator)を変更しても、
イテレータを使う側には変更の必要がない。
例)
変更前:数え方→集合体へ要素を追加した順番(FIFO)
変更前:数え方→集合体へ要素を追加した逆の順番(FILO)
<?php namespace DP\Iterator; /** * 何か(=本)の集合体を数える人[Iterator] * * Class BookShelfIterator * @package DP\Iterator */ class BookShelfIterator { private $bookShelf; private $index; public function __construct(BookShelf $bookShelf) { $this->bookShelf = $bookShelf; - $this->index = 0; + $this->index = $this->bookShelf->getLength() - 1; } public function hasNext(): bool { - return $this->index < $this->bookShelf->getLength(); + return $this->index >= 0; } public function next(): Book { $book = $this->bookShelf->getBookAt($this->index); - $this->index++; + $this->index--; return $book; } }
実行結果
$ php contextIterator_FILO.php ミッケ! かいけつゾロリ 星の王子様
イテレータ、便利だしスマートですね!
しかし未だ、これイテレータパターン使えるっ
って言う場面に直面したことがないので、
何か集合体を見つけては、ソースに落とし込むとかして
そういう直感を養っていこうと思います。