Iteratorパターンとは

リストの内部構造を隠したまま、それぞれの要素にアクセスさせるためのAPIを提供するパターンのこと。

GoF本では、以下のように定義されている。

集約オブジェクトが基にある内部表現を公開せずに、その要素に順にアクセスする方法を提供する。

図にするとこんな感じ。
f:id:sho322:20130611005521j:image
・Iteratorクラス
要素にアクセスするためのAPIを提供する

・ConcreteIteratorクラス
Iteratorで定義されたAPIを実装する。

・Aggregateクラス
Iteratorオブジェクトを返すAPIを提供する

・ConcretaAggregateクラス
リスト固有のIteratorオブジェクトを返す

PHPでIteratorパターン

まずは友達を表すオブジェクト。こいつを走査することになる。

<?php
class FriendBean {
	private $name;
	private $age;
	private $job;

	public function __construct($name, $age, $job) {
		$this->name = $name;
		$this->age = $age;
		$this->job = $job;
	}
	public function getName() {
		return $this->name;
	}
	public function getAge() {
		return $this->age;
	}

	public function getJob() {
		return $this->job;
	}
}

上の友達Beanを配列にして格納するオブジェクト。
IteratorAggregateをimplementsしてる。

<?php
require_once FriendBean.php;
?>
<?php
class Friends implements IteratorAggregate {
	private $friends;
	public function __construct() {
		$this->friends = new ArrayObject();
	}

	public function add(FriendBean $friendBean) {
		$this->friends[] =$friendBean;
	}

	public function getIterator() {
		return $this->friends->getIterator();
	}
}
?>

・友達Beanを特定の条件で絞って走査するオブジェクト

<?php
require_once FriendBean.php;
?>
<?php
class ProgrammerIterator extends FilterIterator {

	public function __construct($iterator) {
		parent::__construct($iterator);
	}

	//FilterIteratorのacceptをovarrideしてる。
	//イテレータの現在の要素がフィルタを満たすかどうかを調べる
	public function accept() {
		//currentは現在の要素を返す
		$friend = $this->current();
		return ($friend->getJob() === PROGRAMMER);
	}
}

?>

で、上のオブジェクト達を使うclient。

<?php
require_once FriendBean.php;
require_once Friends.php;
require_once ProgrammerIterator.php;
?>
<?php
	$friends = new Friends();
	$friends->add(new FriendBean(Mizky, 28, PROGRAMMER));
	$friends->add(new FriendBean(Yoshida,30, POLICEMAN));
	$friends->add(new FriendBean(sho322, 28, PROGRAMMER));
	$friends->add(new FriendBean(Mita, 29, ELEKIMEN));

	$iterator = $friends->getIterator();


	echo <ul>;
	//iterator=>validは現在位置が有効かどうかを調べるメソッド。
	//JavaのhasNextみたいなものだと思う。
	while ($iterator->valid()) {
		$friendBean = $iterator->current();
		printf(<li>%s (%d, %s)</li>,
				$friendBean->getName(),
				$friendBean->getAge(),
				$friendBean->getJob()
		);
		$iterator->next();
	}

	echo </ul>;
	echo <hr>;

	$iterator->rewind();
	$progIterator = new ProgrammerIterator($iterator);
	foreach ($progIterator as $friendBean) {
		printf(<li>%s (%d, %s)</li>,
				$friendBean->getName(),
				$friendBean->getAge(),
				$friendBean->getJob()
		);
	}
	echo </ul>;
	echo <hr>;

?>

ブラウザでクライアントを開くと以下のように表示される。

Mizky (28, PROGRAMMER)
Yoshida (30, POLICEMAN)
sho322 (28, PROGRAMMER)
Mita (29, ELEKIMEN)
------------------------
Mizky (28, PROGRAMMER)
sho322 (28, PROGRAMMER)

参考文献

PHPによるデザインパターン入門

PHPによるデザインパターン入門

  • 作者: 下岡秀幸,道端良,畑勝也
  • 出版社/メーカー: 秀和システム
  • 発売日: 2006/11
  • メディア: 大型本
  • 購入: 4人 クリック: 39回
  • この商品を含むブログ (29件) を見る

PHPを勉強しながらデザインパターンを学ぶことができる非常に貴重な本。
その言語でオブジェクト指向プログラミングを身につけるには、デザインパターンを実装してみるのが一番だと思う。

感謝のプログラミング

今回で感謝のプログラミングは【444時間目】
10000時間まで、あと【9556時間】