デザインパターンを学習しよう【1. Iteratorパターン-1】

株式会社オズビジョンのユッコ (@terra_yucco) です。
デザインパターンの 2 記事目になります。実際のデザインパターンの説明を見ていきます。
前回から随分時間が空いてしまい、またそこまで進んでいないのですが、定期的に上げられるようにやっていきます。

# 教材
[変わらず](https://www.techscore.com/tech/DesignPattern/index.html/)です。

## [1. Iteratorパターン](https://www.techscore.com/tech/DesignPattern/Iterator/Iterator1.html/)
### 1.1 Itaratorパターンとは

Iterator パターンは比較的理解しやすい。Iterator は　Iterate(繰り返す) の名詞形。リストや辞書のような、複数の要素を集約して持つオブジェクトの各要素に順にアクセスする方法を提供するパターン。

例えばいわゆるリストを表現する List クラスの場合、走査方法はいろいろ考えられるが、それをすべて List クラスで提供するのは現実的ではない。そのため、走査方法を与えるクラスは独立に実装し、利用する形とする。

走査クラスを独立にすることで、集約オブジェクト側 List クラスに変更が入っても、変更するべき点を少なく抑えることができる。

### 1.2 サンプルケース

>サンプルケースでは、あなたが学校の先生であることを考えてみましょう。 あなたは、ある学校の新任の先生で、あるクラスの担任を任せられました。 あなたが担任している「生徒」は５人いるものとします。 「生徒」を表すクラス Student クラスは、以下のように定義しましょう。

```php:Student.php
<?php
class Student
{
    /**
     * @var string
     */
    private $name;

    /**
     * @var int
     */
    private $sex; // 0:男, 1:女

    /**
     * @param string $name
     * @param int    $sex
     */
    public function __construct($name, $sex)
    {
        $this->name = $name;
        $this->sex = $sex;
    }

    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @return int
     */
    public function getSex()
    {
        return $this->sex;
    }
}
```

>生徒は名前、性別を表すメンバ変数 name 、sexを持ち、名前を返す getName() メソッドと、性別を返す getSex() メソッドを持ちます。 これらの生徒を管理するために学校から先生に名簿が支給されます。学校から与えられる名簿は以下のように記述されています。

```php:StudentList.php
<?php
//require_once(<PATH> . 'Student.php');

class StudentList
{
    /**
     * @var array
     */
    protected $students;

    /**
     * @var int
     */
    private $last = 0;

    /**
     * @param int
     */
    public function __construct() {
        $this->students = array();
    }

    /**
     * @param Student $student
     */
    public function add($student)
    {
        $this->students[$this->last] = $student;
        $this->last++;
    }

    /**
     * @param int $index
     * @return Student
     */
    public function getStudentAt($index)
    {
        return $this->students[$index];
    }

    /**
     * @return int
     */
    public function getLastNum()
    {
        return $this->last;
    }
}
```

>あなたは、学校から支給されたこの「StudentList」クラスを自由に拡張して利用することができるものとします。
>また、この学校では、先生に対して「先生かくあるべき」という文書として、先生に求める能力を定義しています。 この第１条に以下のような条文があります。

>第１条　先生は、学校から与えられた名簿に自分の生徒を書き込むことができること
>第２条　先生は、生徒の名前を名簿の記載順に呼ぶことができること

```php:Teacher.php
<?php
abstract class Teacher
{
    protected $studentList;

    abstract public function createStudentList();
    abstract public function callStudents();
}
```

### [1.2a （実習課題1）](https://www.techscore.com/tech/DesignPattern/Iterator/Iterator2.html/)

>「Teacher」抽象クラスを継承する MyTeacher クラスと、「StudentList」クラスを拡張した MyStudentList クラスを設計しクラス図を作成しなさい。また、これらのクラスを実装し、 下記のMain クラスを実行しなさい。この２つのクラス以外のクラスやインタフェースを自由に追加しても問題ありません。 MyTeacher クラスの callStudents メソッドでは、あなたのクラスの生徒を順番に標準出力に出力するようにしなさい。

>あなたのクラスの生徒は、

>赤井亮太　男
赤羽里美　女
岡田美央　女
西森俊介　男
中ノ森玲菜　女
の5人とします。

```php:Main.php
<?php
require_once './MyTeacher.php';

class Main
{
    public function work1()
    {
        $you = new MyTeacher();
        $you->createStudentList();
        $you->callStudents();
    }
}

$main = new Main();
$main->work1();
```

#### 初期状態

まず最初に MyTeacher をガラで以下のように実装しました。

```php:MyTeacher.php
<?php
require_once './Teacher.php';
class MyTeacher extends Teacher
{
    public function createStudentList()
    {
        echo 'createStudentList' . PHP_EOL;
    }

    public function callStudents()
    {
        echo 'callStudents' . PHP_EOL;
    }
}
```

実行結果は以下の通り。

```terminal
$ php Main.php
createStudentList
callStudents
```

#### 実装

細かい仕様は未定なので、敬称の「くん」「さん」だけ出し分けてみました。

```php:MyTeacher.php
<?php
require_once './Teacher.php';
require_once './Student.php';

class MyTeacher extends Teacher
{
    public function createStudentList()
    {
        $this->studentList = array(
            new Student('赤井亮太', '男'),
            new Student('赤羽里美', '女'),
            new Student('岡田美央', '女'),
            new Student('西森俊介', '男'),
            new Student('中ノ森玲菜', '女'),
        );
    }

    public function callStudents()
    {
        foreach ($this->studentList as $student) {
            echo $student->getName() . $this->getTitle($student->getSex()) . PHP_EOL;
        }
    }

    private function getTitle($sex)
    {
        return $sex === '男' ? 'くん' : 'さん';
    }
}
```

実行結果は以下の通り。

```terminal
$ php Main.php
赤井亮太くん
赤羽里美さん
岡田美央さん
西森俊介くん
中ノ森玲菜さん
```

## Conclusion

まだ全然デザインパターンが出てきていませんが、まずはここまで。
次回、やっと Iterator パターンが出てきそうです。