📖

Strategyパターンのメリット

に公開

またまたデザインパターンの話となるが、今回は外部から振る舞いを注入してあげるパターンを紹介する。

テンプレートメソッドPatternとの違い

template methodパターンは、全体を継承オーバーライドして、複数の具象クラスで使えるようにするパターンである。ただ、これだとクラスが大きくなった時に拡張性がないことが問題である。

そこで、別の部外者としてふるまいを注入してあげることにより、少ないコードで多くのバリエーションを与えることができる。

具体的に

動物の振る舞いをテンプレートメソッドパターンで表現してみる。

抽象クラス

abstract class Animal
{
    // テンプレートメソッド:一日の流れを定義
    public function dailyRoutine()
    {
        $this->wakeUp();
        $this->eat();
        $this->makeSound();
        $this->move();
        $this->sleep();
    }

    // 共通の振る舞い
    protected function wakeUp()
    {
        echo "目を覚ます🌞\n";
    }

    protected function sleep()
    {
        echo "眠る🌙\n";
    }

    // サブクラスが実装する抽象メソッド
    abstract protected function eat();
    abstract protected function makeSound();
    abstract protected function move();
}

具象クラス

class Dog extends Animal
{
    protected function eat()
    {
        echo "ドッグフードを食べる🍖\n";
    }

    protected function makeSound()
    {
        echo "ワンワン!🐶\n";
    }

    protected function move()
    {
        echo "元気に走り回る🏃‍♂️\n";
    }
}

このように、抽象クラスがふるまいを持っており、具象クラスでオーバーライドして使用している。

次はストラテジーパターンを見ていこう。

interface QuackBehavior {
    public function quack(): void;
}
abstract class Animal {
    protected QuackBehavior $quackBehavior;

    public function performQuack(): void {
        $this->quackBehavior->quack();
    }

    public function setQuackBehavior(QuackBehavior $qb): void {
        $this->quackBehavior = $qb;
    }

    abstract public function display(): void;
}
class DuckQuack implements QuackBehavior {
    public function quack(): void {
        echo "ガーガー!🦆\n";
    }
}
class GooseQuack implements QuackBehavior {
    public function quack(): void {
        echo "グワッグワッ!🪿\n";
    }
}

class Duck extends Animal {
    public function __construct() {
        $this->quackBehavior = new DuckQuack();
    }

    public function display(): void {
        echo "ぼくはカモだよ!🦆\n";
    }
}
class Goose extends Animal {
    public function __construct() {
        $this->quackBehavior = new GooseQuack();
    }

    public function display(): void {
        echo "わたしはガチョウよ!🪿\n";
    }
}

これにより、ガチョウがガーガー!ともグワッグワッ!ともなけることができる。

Animal内に対して、DuckやGooseを注入したときに、interfaceによりDuckQuackとGooseQuackを外部から入れることができるからである。

Discussion