PHP5でデザインパターン − Decoratorパターン

前回のStrategyに続いて、Decoratorパターンです。本では第二章はObserverですが、ちょっとスルー。

http://studio-m.heteml.jp/pattern/decorator/ramen/class.gif

今回の構成は、ラーメンと、それに対するトッピングとなっています。

まずは、ラーメンの抽象クラスとそれを実装するサブクラス(しょうゆラーメンクラスと塩ラーメンクラス)。

Ramen.php

<?php
/**
 * Decoratorパターンによるラーメン
 */

/**
 * Ramen
 */
abstract class Ramen {
    protected $description;
    protected $price;

    public function getDescription()
    {
        return $this->description;
    }

    public function cost()
    {
        return $this->price;
    }
}

/**
 * SoySauceRamen
 */
class SoySauceRamen extends Ramen {
    public function __construct()
    {
        $this->description = 'しょうゆラーメン';
        $this->price = 600;
    }
}

/**
 * SaltRamen
 */
class SaltRamen extends Ramen {
    public function __construct()
    {
        $this->description = '塩ラーメン';
        $this->price = 650;
    }
}

次に、トッピングの抽象クラスとそれを実装するサブクラス(煮卵クラスとキムチクラス)。

Topping.php

<?php
/**
 * Decoratorパターンによるラーメンのトッピング
 */

/**
 * Topping
 */
abstract class Topping extends Ramen {
    protected $ramen;

    public function getDescription()
    {
        return $this->ramen->getDescription().' + '.$this->description;
    }

    public function cost()
    {
        return $this->ramen->cost()+$this->cost;
    }
}

/**
 * BoilingEgg
 */
class BoilingEgg extends Topping {
    public function __construct($ramen)
    {
        $this->ramen = $ramen;
        $this->description = '煮卵';
        $this->cost = 100;
    }
}

/**
 * Kimchi
 */
class Kimchi extends Topping {
    public function __construct($ramen)
    {
        $this->ramen = $ramen;
        $this->description = 'キムチ';
        $this->cost = 70;
    }
}

そして、クライアントとなるテストスクリプト

RamenHouse.php

<?php
/**
 * Decoratorパターンによるラーメン屋
 */

require_once 'Ramen.php';
require_once 'Topping.php';

echo "注文:しょうゆラーメン<br>\n";
$order1 = new SoySauceRamen();
echo $order1->getDescription()."<br>\n";
echo $order1->cost()."円<br><br>\n";

echo "注文:塩ラーメンに煮卵<br>\n";
$order2 = new SaltRamen();
$order2 = new BoilingEgg($order2);
echo $order2->getDescription()."<br>\n";
echo $order2->cost()."円<br><br>\n";

echo "注文:しょうゆラーメンにキムチと煮卵<br>\n";
$order3 = new SoySauceRamen();
$order3 = new Kimchi($order3);
$order3 = new BoilingEgg($order3);
echo $order3->getDescription()."<br>\n";
echo $order3->cost()."円<br><br>\n";

実際の動作結果はこちら
トッピングでラーメンをラッピングしています。動作原理は分かるんだけど、実際の開発でどう使うかは今ひとつしっくりきていません…むむむ。

Head Firstデザインパターン ―頭とからだで覚えるデザインパターンの基本

Head Firstデザインパターン ―頭とからだで覚えるデザインパターンの基本