Proxy パターンとは
Proxy(プロキシ、代理人)とは、大まかに言えば、別の物のインタフェースとして機能するクラスである。その「別の物」とは何でもよく、ネットワーク接続だったり、メモリ上の大きなオブジェクトだったり、複製がコスト高あるいは不可能な何らかのリソースなどである。
proxy(代理人)というのは、仕事を行うべき本人の代わりとなる人。本人でなくてもできるような仕事をまかせるために代理人を立てる。 オブジェクト指向では、「本人」も「代理人」もオブジェクトとなる。忙しくてその仕事ができない本人オブジェクトの代わりに、代理人オブジェクトが(ある程度)仕事をこなしてやることになる。
example
ここで作るサンプルプログラムは、「名前つきのプリンタ」。このプリンタは画面に文字を表示する。
まずPrinterProxyクラスのインスタンス(代理人)を生成する。そのインスタンスには「Alice」という名前をつけ、その名前を表示する。その後「Bob」という名前に変更し、その名前を表示する。名前の設定のや取得では、まだ本物のPrinterクラスのインスタンス(本人)は生成していない。名前の設定と取得という部分は、PrinterProxyクラスが代理で行う。最後にPrintメソッドを呼び出して、実際にプリントを行う段階になってはじめて、PrinterProxyクラスはPrinterクラスのインスタンスを生成する。
ここでは、Printerクラスのインスタンス生成にとても時間がかかるという前提で、プログラムを作成している。コンストラクタからheavyJobメソッドを呼び出し、わざと「重い仕事」をさせている。
Printableクラス
Printer、PrinterProxyクラスの共通インターフェース
<?php interface Printable { public function setPrinterName(string $name); public function getPrinterName(): string; public function print(string $string); }
PrinterProxyクラス
名前つきのプリンタを表すクラス(代理人)
<?php class PrinterProxy implements Printable { private $name; private $real; public function __construct(string $name) { $this->name = $name; } public function setPrinterName(string $name) { if ($this->real !== null) { $this->real->setPrinterName($name); } $this->name = $name; } public function getPrinterName(): string { return $this->name; } public function print(string $string) { $this->realize(); $this->real->print($string); } private function realize() { if ($this->real === null) { $this->real = new Printer($this->name); } } }
Printerクラス
名前つきのプリンタを表すクラス(本人)
<?php class Printer implements Printable { private $name; public function __construct(string $name) { $this->name = $name; $this->heavyJob("Printerのインスタンス(" . $this->name . ")を生成中"); } public function setPrinterName(string $name) { $this->name = $name; } public function getPrinterName(): string { return $this->name; } public function print(string $string) { echo "=== {$this->name} ===" . PHP_EOL; echo $string; } private function heavyJob(string $msg) { echo $msg; for ($i = 0; $i < 5; $i++) { sleep(1); echo "."; } echo "完了." . PHP_EOL; } }
Main
<?php $p = new PrinterProxy("Alice"); echo "名前は現在" . $p->getPrinterName() . "です。" . PHP_EOL; $p->setPrinterName("Bob"); echo "名前は現在" . $p->getPrinterName() . "です。" . PHP_EOL; $p->print("Hello, world.");
実行結果
$ php Main.php 名前は現在Aliceです。 名前は現在Bobです。 Printerのインスタンス(Bob)を生成中.....完了. === Bob === Hello, world.#
ソースコード
役割
Subject役
Proxy役とRealSubject役を同一視するためのインターフェースを定める。 サンプルコードにおけるPrintableインターフェース
Proxy役
Proxy役はClient役からの要求をできるだけ処理する。もし自分だけで処理できなかったら、Proxy役はRealSubject役に仕事を任せる。 Proxy役は、ほんとうにRealSubject役が必要になってからRealSubject役を生成する。Proxy役はSubject役で定められているインターフェースを実装している。 サンプルコードにおけるPrinterProxyクラス。
RealSubject役
代理人のProxy役で手に負えなくなったときに登場するのが、本人のRealSubject役。 サンプルコードにおけるPrinterクラス。
Client役
Proxyパターンの利用者。 サンプルコードにおけるMain。
まとめ
- 代理人を使うことで処理を高速化する
- HTTPプロキシ
- これもProxyパターンに当てはめて考えることができる。WebブラウザがClient、HTTPプロキシがProxy、WebサーバがRealSubject役。
関連パターン
- 作者: 結城浩
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2004/06/19
- メディア: 大型本
- 購入: 51人 クリック: 762回
- この商品を含むブログ (399件) を見る