引用記事
この記事を書くきっかけになったブログです。
記事内の解説やソースコードは、こちらのブログと著者の公開リポジトリを参考にしています。
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);