デザインパターンから学ぶオブジェクト指向 【01. Iterator】
デザインパターンを知識として持っているだけでなく、実務で使って楽をしたい。
そう思ったのでもう一度勉強し直しです。
注意したのは以下の点です。
デザインパターンを知っただけ → そのデザインパターンだけしか使えない
これは本当に避けたい!
以前の勉強はまさにこれに陥っていて、実務で活かしきれていませんでした。
ということで今回のテーマはこれです。
デザインパターンを学ぶのではなく、オブジェクト指向の概念を学ぶ。
オブジェクト指向の概念を理解し、うまく設計できるようにしたい。
自分はテキストでは頭に入らない弱小脳なので、頭への定着も兼ねてスライドを作成しました。
どこかで使えるかもしれないし。
今回は Iteratorパターン。
実装したコード
スライド中のコードに加え、ちょっとした補足(複数の走査方法の実装など)も加えたコードを以下に記載します。
Step1. 普通に配列を使って実装する
<?php class ConcreteAggregate { private $aggregate = array(); private $index = 0; public function add($element) { $this->aggregate[$this->index] = $element; $this->index++; } public function getItemAt($i) { return $this->aggregate[$i]; } public function length() { return count($this->aggregate); } } class Worker { public function output() { $aggregate = new ConcreteAggregate(); $aggregate->add("zero"); $aggregate->add("one"); $aggregate->add("two"); for ($i = 0; $i < $aggregate->length(); $i++ ) { echo $aggregate->getItemAt($i) . "\n"; } } } $worker = new Worker(); $worker->output();
Step2. インターフェースを実装する
<?php interface MyIterator { public function hasNext(); public function next(); } // 順方向走査のAggregate class ConcreteAggregate implements MyIterator { private $aggregate = array(); private $addIndex = 0; private $nextIndex = 0; public function add($element) { $this->aggregate[$this->addIndex] = $element; $this->addIndex++; } public function hasNext() { return ($this->nextIndex < $this->length()); } public function next() { return $this->aggregate[$this->nextIndex++]; } public function length() { return count($this->aggregate); } } // 逆方向走査のAggregate class ConcreteAggregateReverse implements MyIterator { private $aggregate = array(); private $addIndex = 0; private $nextIndex = -1; public function add($element) { $this->aggregate[$this->addIndex] = $element; $this->addIndex++; $this->nextIndex++; } public function hasNext() { return ($this->nextIndex >= 0); } public function next() { return $this->aggregate[$this->nextIndex--]; } public function length() { return count($this->aggregate); } } class Worker { public function output() { $aggregate = new ConcreteAggregate(); // $aggregate = new ConcreteAggregateReverse(); // 逆方向にしたければこちらを使う $aggregate->add("zero"); $aggregate->add("one"); $aggregate->add("two"); while ($aggregate->hasNext()) { echo $aggregate->next() . "\n"; } } } $worker = new Worker(); $worker->output();
Step3. クラスの責任を分離する
<?php interface MyAggregate { public function iterator(); } interface MyIterator { public function hasNext(); public function next(); } class ConcreteAggregate implements MyAggregate { private $aggregate = array(); private $index = 0; public function add($element) { $this->aggregate[$this->index] = $element; $this->index++; } public function getItemAt($i) { return $this->aggregate[$i]; } public function length() { return count($this->aggregate); } public function iterator() { return new ConcreteIterator($this); // return new ConcreteIteratorReverse($this); // 逆方向にしたければこちらを使う } } // 順方向走査Iterator class ConcreteIterator implements MyIterator { private $aggregate; private $index = 0; public function __construct($concreteAggregate) { $this->aggregate = $concreteAggregate; } public function hasNext() { return ($this->index < $this->aggregate->length()); } public function next() { return $this->aggregate->getItemAt($this->index++); } } // 逆方向走査Iterator class ConcreteIteratorReverse implements MyIterator { private $aggregate; private $index; public function __construct($concreteAggregate) { $this->aggregate = $concreteAggregate; $this->index = $this->aggregate->length() - 1; } public function hasNext() { return ($this->index >= 0); } public function next() { return $this->aggregate->getItemAt($this->index--); } } class Worker { public function output() { $aggregate = new ConcreteAggregate(); $aggregate->add("zero"); $aggregate->add("one"); $aggregate->add("two"); $iterator = $aggregate->iterator(); while ($iterator->hasNext()) { echo $iterator->next() . "\n"; } } } $worker = new Worker(); $worker->output();