※学習用メモ デザインパターン:Template Method編[PHP]

# はじめに
使用している言語はPHPです。(自分が良く使うので)

## Template Methodパターンとはどういうものか
スーパークラスと呼ばれるクラスで処理の大きな枠組みを決め、
サブクラスと呼ばれるクラスで具体的な内容を記述するというデザインパターンのこと。

**似たような処理を共通化させたい**際に用いられることが多い

## Template Methodパターンを用いるメリット/デメリット
* メリット
 * スーパークラスに主なロジックが記述されているため、バグが生じた際にスーパークラス内に記述されているTemplateMethodを修正すればよい
 * サブクラスの内容が簡潔になる

* デメリット
 * サブクラスの数が増加するケースが多い
 * 親子関係が密接であるのでスーパークラスのロジックを確認したうえでないと実装することが難しい
 * スーパークラスの処理が大きくなると、サブクラスの自由度が小さくなってしまう

## サンプルコード
### 仕様
父親とその子どもの一日の行動(平日)を文字列表示する。(いい例が思いつかなかった)

以下のクラスを用意します。

* OneDayDisplayクラス:抽象クラス
 * 一日の行動を文字列表示(Template Method)
 * その他朝・昼・夜・深夜の行動を抽象メソッドで定義しておく

* 具象クラス
 * OneDayOfFatherクラス:父親の一日の具体的な行動
 * OneDayOfChildクラス:子どもの一日の具体的な行動

では実際に書いてみる

### 抽象クラス
```OneDayDisplay.class.php
abstract class OneDayDisplay
{
    abstract protected function morning();
    abstract protected function noon();
    abstract protected function night();
    abstract protected function midnight();

    // 一日の行動の表示
    public function oneDayToString()
    {
        echo '朝:' . $this->morning() . PHP_EOL;
        echo '昼:' . $this->noon() . PHP_EOL;
        echo '夜:' . $this->night() . PHP_EOL;
        echo '深夜:' . $this->midnight() . PHP_EOL;
    }
}
```

上記抽象クラスで朝・昼・夜・深夜の行動を記述するための抽象メソッドを定義。
共通なメソッド(Template Method)としてoneDayToString()を用意し、
こちらでそれぞれの行動を出力できるような形とした。

### 具象クラス

```OneDayOfFather.class.php
class OneDayOfFather extends OneDayDisplay
{
    protected function morning()
    {
        return '出社';
    }
    
    protected function noon()
    {
        return '外食';
    }
    
    protected function night()
    {
        return '残業';
    }
    
    protected function midnight()
    {
        return '晩酌';
    }
}
```

具象クラスで抽象クラス側で定義した抽象メソッドの具体的な内容を定義する。

```OneDayOfChild.class.php
class OneDayOfChild extends OneDayDisplay
{
    protected function morning()
    {
        return '登校';
    }
    
    protected function noon()
    {
        return '給食';
    }
    
    protected function night()
    {
        return 'ゲーム';
    }
    
    protected function midnight()
    {
        return '睡眠';
    }
}
```

こちらの具象クラスでは先ほどとは異なる内容で定義。

### 呼び出してみる
```php
$oneDayOfFather = new OneDayOfFather();
$oneDayOfFather->oneDayToString();

$oneDayOfChild = new OneDayOfChild();
$oneDayOfChild->oneDayToString();

/* 以下出力
朝:出社
昼:外食
夜:残業
深夜:晩酌
朝:登校
昼:給食
夜:ゲーム
深夜:睡眠
*/
```

### 出力がなんか味気ない....
こう感じた場合先ほどメリットで挙げたように、抽象クラス側の共通メソッドに微修正を加えればよい。

```OneDayDisplay.class.php
abstract class OneDayDisplay
{
    abstract protected function morning();
    abstract protected function noon();
    abstract protected function night();
    abstract protected function midnight();

    // 一日の行動の表示(少し装飾)
    public function oneDayToString()
    {
        echo '*-------1日の流れ------*' . PHP_EOL;
        echo '朝:' . $this->morning() . PHP_EOL;
        echo '昼:' . $this->noon() . PHP_EOL;
        echo '夜:' . $this->night() . PHP_EOL;
        echo '深夜:' . $this->midnight() . PHP_EOL;
        echo '*----------------------*' . PHP_EOL;
    }
}
```

出力してみる

```php
$oneDayOfFather = new OneDayOfFather();
$oneDayOfFather->oneDayToString();

$oneDayOfChild = new OneDayOfChild();
$oneDayOfChild->oneDayToString();


/* 以下出力
*-------1日の流れ------*
朝:出社
昼:外食
夜:残業
深夜:晩酌
*----------------------*
*-------1日の流れ------*
朝:登校
昼:給食
夜:ゲーム
深夜:睡眠
*----------------------*
*/
```

## まとめ
**似た流れを共通化する**ということにより同じようなクラスを複数作成する必要がなくなり、
同様な処理の修正の際も一点を修正すればよくなるという**メリット**は大きい。

しかし業務などでの大きなプロジェクトで使用する際には**デメリット**部分にも注意しどのような設計で開発を進めるか検討する必要はありそうと感じた。