【PHPデザインパターン】05_Façade~シンプルな唯一の窓口


引用記事

この記事を書くきっかけになったブログです。

記事内の解説やソースコードは、こちらのブログと著者の公開リポジトリを参考にしています。

Do You PHP はてな〜[doyouphp][phpdp]PHPによるデザインパターン入門 - Façade~シンプルな唯一の窓口

概要

  • サブシステム内に存在する複数のインターフェースに1つの統一インターフェースを与える。
  • 複雑に連携しあうクラスやオブジェクトを容易に扱うための窓口(API)を提供する。
  • クライアントからはサブシステムの入り口しか見えなくなり、同時にサブシステムとの結びつきがゆるくなる。その結果、互いの独立性が高くなる。
  • 非常に大きな「カプセル化」を行なっている。
  • 「façade」は「ファサード」と読む。(フランス語で「正面窓口」という意味)

構成要素

Façadeクラス

  • サブシステムで提供される統一APIを持つクラス。
  • サブシステム内のクラス同士の関係を知っている。

サブシステム内のクラス群

  • サブシステムを構成するクラス群。
  • Façadeクラスの存在は知らない。

Clientクラス

  • サブシステムを利用するクラス。
  • Façadeクラスを通じてサブシステムにアクセスする。
  • サブシステム内のクラス同士の関係は見えない。

実演

著者のソースコードと比べると、かなり簡単な内容になっています。

処理の流れ

  • 注文データを配列形式で受け取り、メッセージを出力する。
  • my_client.phpはClientクラスに該当する。
  • ManagerクラスはFaçadeクラスに該当する。
  • OrderクラスCalcMessageクラスをサブシステムとする。
  • Orderクラスで注文情報をセットする。
  • CalcMessageクラスで合計金額を計算し、注文内容のメッセージを出力する。

ファイル構造

MyFacade
   ├── CalcMessage.php
   ├── Manager.php
   ├── Order.php
   └── my_client.php

ソースコード

my_client.php

my_client.php
<?php
namespace DoYouPhp\PhpDesignPattern\Facade\MyFacade;
require dirname(dirname(__DIR__)).'/vendor/autoload.php';

use DoYouPhp\PhpDesignPattern\Facade\MyFacade\Manager;
use DoYouPhp\PhpDesignPattern\Facade\MyFacade\Order;
use DoYouPhp\PhpDesignPattern\Facade\MyFacade\CalcMessage;

// 配列型の注文データ
$order_data = array(1, 'りんご', 100, 3);

// Managerクラスを窓口にして必要な処理を行う
Manager::order($order_data);

Manager.php

Manager.php
<?php
namespace DoYouPhp\PhpDesignPattern\Facade\MyFacade;

use DoYouPhp\PhpDesignPattern\Facade\MyFacade\Order;
use DoYouPhp\PhpDesignPattern\Facade\MyFacade\CalcMessage;

class Manager
{
    // 注文データを元にサブシステムで必要な処理を行わせる
    public function order($order_data)
    {
        // Orderクラスのインスタンスを生成し、必要なプロパティがセットされる
        // Singletonパターンを利用してオブジェクトの複製を防いでいる
        $order = Order::getInstance($order_data);

        // CalcMessageクラスのインスタンスを生成する
        // 注文内容を計算し、メッセージを返す
        $calc_message = new CalcMessage($order);
        $calc_message->createMessage();

        // cloneを試して複製できないことを確認する
        try {
            $order_clone = clone $order;
        } catch (\RuntimeException $e) {
            echo $e->getMessage().'<br>'."\n";
        }
    }
}

Order.php

Order.php
<?php
namespace DoYouPhp\PhpDesignPattern\Facade\MyFacade;

// 注文内容をプロパティとして保有する
class Order
{
    private $id;
    private $name;
    private $price;
    private $amount;
    // $instanceはオブジェクト型のプロパティ
    private static $instance;

    // 配列型の注文データからプロパティをセットする
    private function __construct($order_data)
    {
        list($this->id, $this->name, $this->price, $this->amount) = $order_data;
    }

    // 他クラスからオブジェクトを生成する場合は、こちらのメソッドを利用する
    // staticメソッドなので、オブジェクト未作成の状態から呼び出せる
    // オブジェクトが存在しない場合のみ、新規にオブジェクトを生成する
    public function getInstance($order_data)
    {
        if (!isset(self::$instance)){
            self::$instance = new Order($order_data);
        }

        return self::$instance;
    }

    // セットしたプロパティを返す
    public function getId()
    {
      return $this->id;
    }

    public function getName()
    {
        return $this->name;
    }

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

    public function getAmount()
    {
        return $this->amount;
    }

    // Singletonパターンを利用してオブジェクトの複製を防ぐ
    final public function __clone()
    {
        throw new \RuntimeException(get_class($this).'クラスのオブジェクトは複製できません');
    }
  }

CalcMessage.php

CalcMessage.php
<?php
namespace DoYouPhp\PhpDesignPattern\Facade\MyFacade;

// 注文合計額を計算しメッセージを返す
class CalcMessage
{
    // $orderはオブジェクト型のプロパティ
    private $order;
    private $order_sum;

    // Orderオブジェクトを引数にして必要なプロパティをセットする
    public function __construct(Order $order)
    {
        $this->order = $order;

        // 価格*個数の値をプロパティにセットする
        $order_price = $this->order->getPrice();
        $order_amount = $this->order->getAmount();
        $this->order_sum = $order_price * $order_amount;
    }

    // 注文内容と計算結果のメッセージを返す
    public function createMessage()
    {
        echo '注文ID'.$this->order->getId().'で'.$this->order->getName().'を注文しました!'.'<br>'."\n";
        echo '注文合計は'.$this->order_sum.'円です!'.'<br>'."\n";
    }
}