圧倒亭グランパのブログ

30年後の自分にもわかるように書くブログ

デザインパターンから学ぶオブジェクト指向 【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();