TemplateMethodパターン

どうも、今月ブログ更新をサボり気味で後悔してます。
「ブログ続けてるのすごい」って言われて嬉しかったので、
更新ちゃんと頑張ります。
遡ってみると2017年1月からブログを始めて早2年経ってました。
累計113記事でした。

\目標、1000記事/

今回は、TemplateMethodについてです。

 

TemplateMethodとは?

メソッドにおけるアルゴリズムの骨組みを定義し、
いくつかの手順をサブクラスに先送りします。

→ アルゴリズムとなる一連の手順(メソッド)を
定義するメソッド(テンプレート)があり、
その一連の手順の中のメソッドの1つ以上を
抽象メソッドとして定義し、
サブクラスがそれを実装する

 

クラス図

テンプレートメソッドのクラス図

 

コード

abstract class AbstractClass
{
    public function templateMethod(): void
    {
        $this->primitiveOperation1();
        $this->primitiveOperation2();
    }

    //それぞれ異なる手順→サブクラスにまかせる
    abstract public function primitiveOperation1();

    public function primitiveOperation2(): void
    {
        //共通の手順
    }
}
class ConcreteClass extends AbstractClass
{
    public function primitiveOperation1(): void
    {
        // TODO: Implement primitiveOperation1() method.
    }
}

 

いざ、実装!

Head Firstデザインパターンの具体例では、
コーヒーと紅茶の作り方がでてきました。

レシピ

▶︎コーヒーの作り方
1.お湯を沸かす
2.フィルターをセットして淹れる
3.コップにコーヒーを注ぐ
4.ミルクや砂糖を加える

▶︎紅茶の作り方
1.お湯を沸かす
2.ティパックをセットしてお湯をいれる
3.レモンをいれる
4.コップに注ぐ

 

ざっくりみると、コーヒーと紅茶の作り方は似ているので、
1~4の一連の手順をテンプレートメソッドとしてスーパークラスに定義し、
「1.お湯を沸かす」の部分は共通化できるので、スーパークラスで実装します。
コーヒーと紅茶で異なる部分はサブクラスで実装します。

実際のコードはこちら↓
[kin29/HeadFirstDezaPata]

テンプレートメソッド適用前と後のbefore-after

 

クラス図

カフェインでのテンプレートメソッド

 

コード

abstract class CaffeineBeverage
{
    public function prepareRecipe(): void
    {
        $this->boilWater();
        $this->brew();
        $this->pourInCup();
        $this->addCondiments();
    }

    abstract public function brew(): void;

    abstract public function addCondiments(): void;

    public function boilWater(): void
    {
        echo "お湯を沸かします\n";
    }

    public function pourInCup(): void
    {
        echo "カップに注ぎます\n";
    }
}

 

class Coffee extends CaffeineBeverage
{
    public function __toString(): string
    {
        return "--- コーヒーのレシピ ---\n";
    }

    public function brew(): void
    {
        echo "フィルターでコーヒをドリップします\n";
    }

    public function addCondiments(): void
    {
        echo "砂糖とミルクを追加します\n";
    }
}

class Tea extends CaffeineBeverage
{
    public function __toString(): string
    {
        return "--- 紅茶のレシピ ---\n";
    }

    public function brew(): void
    {
        echo "紅茶を浸します\n";
    }

    public function addCondiments(): void
    {
        echo "レモンを追加します\n";
    }
}
$ php src/TemplateMethod/main.php
--- コーヒーのレシピ ---
お湯を沸かします
フィルターでコーヒをドリップします
カップに注ぎます
砂糖とミルクを追加します
--- 紅茶のレシピ ---
お湯を沸かします
紅茶を浸します
カップに注ぎます
レモンを追加します

メリット

・共通メソッドの変更が必要となった場合、
スーパクラスの変更のみでいい。

・スーパクラスで骨組みを定義しているので、
新しいカフェインクラスの追加が必要になった場合(例えばココアとか?)、
実装がしやすい

 

 

令和もがんばろーっっと