【デザインパターン】PHPでTemplate Methodパターンの実装をしてみた

## 環境
 - PHP 7.2.18

## Template Methodパターンとは
Template とと言うのは、よくいろんな人が「テンプレ」などと略すアレです。
メールなどの定型文や、作品のベースとなるひな形などの「決まった様式」のことを指すことが多いですよね。
Template Methodパターンの名前の由来もそこからきていて、決まった処理の流れなどを抽象クラスで「枠」として定めて、具体的な実装の内容は具象クラスで実装するものとなります。

<img width="881" alt="スクリーンショット 2020-06-23 0.18.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183984/e94c6507-8b60-c2c1-0799-cb094ab93906.png">

## Template Methodパターンは何がいいか
Template Methodパターンを使うことで、似たような処理、繰り返し使われるような処理を共通化することができます。
関数による処理の共通化をすることもあるとは思いますが、クラスでそれを行うのがTemplate Methodパターンといったところです。

## 例題の概要
例として簡単なプログラムを作りました。
「鳥の情報を返す」テンプレートに対して、具体的な鳥のクラス（カラス,ペンギン,ダチョウ）を実装して処理を共通化させました。
最終的にそれぞれの鳥の情報を表に表示します。
イメージ図とクラス図です。

### イメージ図
<img width="451" alt="スクリーンショット 2020-06-23 0.20.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183984/4e404ad2-281f-5ccd-4ce6-60cf736e218f.png">

### クラス図
<img width="1141" alt="スクリーンショット 2020-06-23 0.19.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183984/93012248-432b-2e6f-5fff-0701ca17bac4.png">

### ファイル構成
![スクリーンショット 2020-06-22 0.06.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183984/61e669ec-7556-6aac-8273-c58eac1bdf30.png)

### ソースコード
https://github.com/nooboolean/template_method_practice

## 実装
### まずは、テンプレートである抽象クラスの定義
今回の実装で共通となる処理は、それぞれのオブジェクト（鳥たち）の「種類」「名前」「出産方法」「移動手段」の情報をこの順番で返す処理です。
「種類」や「出産方法」などの、鳥であれば共通となる情報は、抽象クラスで実装してしまっています。
その他の鳥の種類ごとに変化する「名前」や「移動手段」に関しては、具体的な実装を具象クラスに任せています。

```php:AbstractBird.php
<?php

abstract class AbstractBird {
    private $birdInfo;
    
    final public function getInfo() {
        $this->birdInfo['type'] = $this->getType();
        $this->birdInfo['name'] = $this->getName();
        $this->birdInfo['birthType'] = $this->getBirthType();
        $this->birdInfo['howToMovement'] = $this->gethowToMovement();
        return $this->birdInfo;
    }

    final private function getType() {
        return '鳥類';
    }

    protected abstract function getName();

    final private function getBirthType() {
        return '卵生';
    }

    protected abstract function gethowToMovement();
}

?>

```
この後は、この抽象クラスを継承した具象クラスで具体的な実装をしていきます。

### 次は具象クラス(カラスクラスなど)の用意
抽象クラスである「鳥」クラスができたので、後はそれらの具体的な実装を書き込む「カラスクラス」などの具象クラスを作成していきます。
「名前」や「移動手段」などの、「鳥」の種類によってそれぞれ変わる情報は、それぞれの鳥の種類のクラスに実装します。
今回は、カラスクラス/ペンギンクラス/ダチョウクラスを作成しました。

```php:Crow.php
<?php
namespace Birds;
require_once('./AbstractBird.php');
use AbstractBird;

class Crow extends AbstractBird {

    final protected function getName() {
        return 'カラス　';
    }

    final protected function gethowToMovement() {
        return '飛ぶ';
    }
}

?>

```

```php:Penguin.php
<?php
namespace Birds;
require_once('./AbstractBird.php');
use AbstractBird;

class Penguin extends AbstractBird {

    final protected function getName() {
        return 'ペンギン';
    }

    final protected function gethowToMovement() {
        return '泳ぐ';
    }
}

?>

```

```php:Ostrich.php
<?php
namespace Birds;
require_once('./AbstractBird.php');
use AbstractBird;

class Ostrich extends AbstractBird {

    final protected function getName() {
        return 'ダチョウ';
    }

    final protected function gethowToMovement() {
        return '走る';
    }
}

?>

```

あとは、この具象クラスを実際に `new` してデータを取得し表示して完了です！

### それぞれの具象クラスを実行して情報の表示
最後にそれぞれのクラスを `new` してデータを取得して表示します。
抽象クラスで処理を共通化しているため、同じ様な処理をこのようにシンプルに管理することができます。

```php:index.php
<?php
require_once('./Birds/Ostrich.php');
require_once('./Birds/Penguin.php');
require_once('./Birds/Crow.php');
use Birds\Ostrich;
use Birds\Penguin;
use Birds\Crow;

$Ostrich = (new Ostrich)->getInfo();
$Penguin = (new Penguin)->getInfo();
$Crow    = (new Crow)->getInfo();


?>

<?php
echo "<table border = '1'>";
echo "   <tr>";
echo "        <th>種類</th>";
echo "        <th>名前</th>";
echo "        <th>出産方法</th>";
echo "        <th>移動手段</th>";
echo "    </tr>";
echo "    <tr>";
echo "        <th>$Ostrich[type]</th>";
echo "        <th>$Ostrich[name]</th>";
echo "        <th>$Ostrich[birthType]</th>";
echo "        <th>$Ostrich[howToMovement]</th>";
echo "    </tr>";
echo "</table>";
?>

<?php
echo "<table border = '1'>";
echo "   <tr>";
echo "        <th>種類</th>";
echo "        <th>名前</th>";
echo "        <th>出産方法</th>";
echo "        <th>移動手段</th>";
echo "    </tr>";
echo "    <tr>";
echo "        <th>$Penguin[type]</th>";
echo "        <th>$Penguin[name]</th>";
echo "        <th>$Penguin[birthType]</th>";
echo "        <th>$Penguin[howToMovement]</th>";
echo "    </tr>";
echo "</table>";
?>

<?php
echo "<table border = '1'>";
echo "   <tr>";
echo "        <th>種類</th>";
echo "        <th>名前</th>";
echo "        <th>出産方法</th>";
echo "        <th>移動手段</th>";
echo "    </tr>";
echo "    <tr>";
echo "        <th>$Crow[type]</th>";
echo "        <th>$Crow[name]</th>";
echo "        <th>$Crow[birthType]</th>";
echo "        <th>$Crow[howToMovement]</th>";
echo "    </tr>";
echo "</table>";
?>

```

## ブラウザ確認
こんな感じで表示されました！完成！
![スクリーンショット 2020-06-23 0.43.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183984/e7cabd2a-72b4-9e4a-e21e-3b47f1b663d3.png)