今回は、ご存知デザパタの
第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 ミッケ! かいけつゾロリ 星の王子様
イテレータ、便利だしスマートですね!
しかし未だ、これイテレータパターン使えるっ
って言う場面に直面したことがないので、
何か集合体を見つけては、ソースに落とし込むとかして
そういう直感を養っていこうと思います。