LoginSignup
0
0

More than 5 years have passed since last update.

【PHPデザインパターン】20_Proxy~具体的な実装を隠す身代わり

Posted at

引用記事

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

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

Do You PHP はてな〜[doyouphp][phpdp]PHPによるデザインパターン入門 - Proxy~具体的な実装を隠す身代わり

概要

  • 「proxy」は「代理」という意味。
  • やりとりをするオブジェクトの間にクッション役を用意し、このクッションに色々な役割を持たせる。
  • あるオブジェクトへのアクセスを制御するために、そのオブジェクトの代理、または入れ物を提供する。
  • 代理オブジェクトにアクセスしているのか目的のオブジェクトにアクセスしているのかを、意識させない。

構成要素

Subjectクラス

  • RealSubjectクラスとProxyクラスが提供する共通のAPIを定義するクラス。

RealSubjectクラス

  • Subjectクラスのサブクラス。

Proxyクラス

  • Subjectクラスのサブクラス。
  • 具体的な処理は、内部に保持したRealSubjectクラスのインスタンスに転送する。
  • RealSubjectクラスに対するアクセス制御や、RealSubjectクラスのインスタンスの生成タイミングなどを調整する。

実演

処理の流れ

  • ItemDaoクラスのメソッドを、各RealSubjectクラス、Proxyクラスで実装する。
  • DbItemDaoクラスでは、配列からデータを読み込んでいる。
  • MockItemDaoクラスでは、ダミーデータを用意する。
  • ItemDaoクラスを使用した場合と、ProxyクラスであるItemDaoProxyクラスを使用した場合の動きを確認する。

ファイル構造

MyProxy
  ├── DbItemDao.php
  ├── Item.php
  ├── ItemDao.php
  ├── ItemDaoProxy.php
  ├── MockItemDao.php
  └── my_client.php

ソースコード

Subjectクラス

ItemDao.php

ItemDao.php
<?php
namespace DoYouPhp\PhpDesignPattern\Proxy\MyProxy;

/**
 * Subjectクラスに相当する
 */
interface ItemDao
{
    public function findById($item_id);
}

RealSubjectクラス

DbItemDao.php

DbItemDao.php
<?php
namespace DoYouPhp\PhpDesignPattern\Proxy\MyProxy;

use DoYouPhp\PhpDesignPattern\Proxy\MyProxy\ItemDao;
use DoYouPhp\PhpDesignPattern\Proxy\MyProxy\Item;

/**
 * RealSubjectクラスに相当する
 */
class DbItemDao implements ItemDao
{
    public function findById($item_id)
    {
        // 配列形式のデータからItem型オブジェクトを生成する
        $item_array = array('0' => array(1, 'apple'), '1' => array(2, 'orange'), '2' => array(3, 'peach'));

        foreach ($item_array as $data) {
            list($id, $name) = $data;

            // IDが合致した場合、Item型オブジェクトを返す
            if ($item_id === $id) {
                $item = new Item($id, $name);

                return $item;
            }
        }
    }
}

MockItemDao.php

MockItemDao.php
<?php
namespace DoYouPhp\PhpDesignPattern\Proxy\MyProxy;

use DoYouPhp\PhpDesignPattern\Proxy\MyProxy\ItemDao;
use DoYouPhp\PhpDesignPattern\Proxy\MyProxy\Item;

/**
 * RealSubjectクラスに相当する
 */
class MockItemDao implements ItemDao
{
    // 商品情報を直接指定し、Item型オブジェクトを生成する
    // IDは流動的、商品名は固定する
    public function findById($item_id)
    {
        $item = new Item($item_id, 'ダミー商品');

        return $item;
    }
}

Proxyクラス

ItemDaoProxy.php

ItemDaoProxy.php
<?php
namespace DoYouPhp\PhpDesignPattern\Proxy\MyProxy;

use DoYouPhp\PhpDesignPattern\Proxy\MyProxy\ItemDao;

/**
 * Proxyクラスに相当する
 * ItemDaoクラスのメソッドを実装している
 */
class ItemDaoProxy
{
    // プロパティ
    private $dao;
    private $cache;

    // コンストラクタ
    public function __construct(ItemDao $dao)
    {
        $this->dao = $dao;
        $this->cache = array();
    }

    // キャッシュを作成する
    public function findById($item_id)
    {
        // キャッシュに該当IDのItemDao型オブジェクトが存在した場合、データを返す
        if (array_key_exists($item_id, $this->cache)) {
            echo 'Proxyで保持しているキャッシュからデータを返します'.'<br>'."\n";

            return $this->cache[$item_id];
        }

        // キャッシュに該当IDのItemDao型オブジェクトが存在しない場合、IDをキーにした配列の要素としてセットする
        // その後、データを返す
        $this->cache[$item_id] = $this->dao->findById($item_id);

        echo 'Proxyでデータのキャッシュを作りました'.'<br>'."\n";
        return $this->cache[$item_id];
    }
}

Modelクラス

Item.php

Item.php
<?php
namespace DoYouPhp\PhpDesignPattern\Proxy\MyProxy;

/**
 * Modelクラスに相当する
 */
class Item
{
    // プロパティ
    private $id;
    private $name;

    // コンストラクタ
    public function __construct($id, $name)
    {
        $this->id = $id;
        $this->name = $name;
    }

    // 各プロパティを取得する
    public function getId()
    {
        return $this->id;
    }

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

Client

my_client.php

my_client.php
<?php
namespace DoYouPhp\PhpDesignPattern\Proxy\MyProxy;

require dirname(dirname(__DIR__)).'/vendor/autoload.php';

use DoYouPhp\PhpDesignPattern\Proxy\MyProxy\ItemDao;
use DoYouPhp\PhpDesignPattern\Proxy\MyProxy\DbItemDao;
use DoYouPhp\PhpDesignPattern\Proxy\MyProxy\MockItemDao;
use DoYouPhp\PhpDesignPattern\Proxy\MyProxy\ItemDaoProxy;

function execute(ItemDao $dao, $use_proxy = false)
{
    // Proxyクラスを使用した場合、ItemDaoProxy型オブジェクトからメソッドが呼ばれる
    if ($use_proxy === true) {
        $dao = new ItemDaoProxy($dao);
    }

    // データを抽出する
    for ($item_id = 1; $item_id <= 3; $item_id++) {
        $item = $dao->findById($item_id);

        echo 'ID:'.$item_id.'、商品名:'.$item->getName().'<br>'."\n";
    }

    // キャッシュの動作を確認するため、再度データを取得する
    $item_id = 1;
    $item = $dao->findById($item_id);
    echo 'ID:'.$item_id.'、商品名:'.$item->getName().'<br>'."\n";
}

echo '---DbItemDao+Proxyなし---'.'<br>'."\n";
execute(new DbItemDao());

echo '---MockItemDao+Proxyなし---'.'<br>'."\n";
execute(new MockItemDao());

echo '---DbItemDao+Proxyあり---'.'<br>'."\n";
execute(new DbItemDao(), true);

echo '---MockItemDao+Proxyあり---'.'<br>'."\n";
execute(new MockItemDao(), true);
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0