ようこそ。睡眠不足なプログラマのチラ裏です。

デザインパターン第12回「Proxyパターン」

公私共にモチベーション低いですが、久しぶりに独りよがりなデザパタ講座です。
今回はGoFデザインパターンより、「Proxyパターン」をぬるーく解説します。

■Proxyパターンの概要■
Proxyとは「代理人」という意味です。


現実の世界での「代理人」のイメージは、弁護士や税理士など、
本人ができない仕事をするという意味合いで使われることが多いが、
GoFのProxyパターンにおいての代理人オブジェクトの役割というのは、
本人ではなくてもできるような処理について、要求を委譲されるオブジェクトのことを言います。
代理人オブジェクトでは処理のできない要求のみを、本人オブジェクトが引き受けて処理をします。
つまり、RealSubject(本人オブジェクト)へのアクセスを制御するために、Proxy(代理人オブジェクト)でRealSubjectをラップします。

生成にコストのかかる要求や、生成に注意を払わなければならないオブジェクトへのアクセスを制御するために、
ProxyはRealSubjectを隠蔽して、あたかも代理人がすべての要求を処理しているかのうような振る舞いを提供するパターンです。


共通のインターフェイス(Subject)を持つインスタンスを内包し、利用者からのアクセスを代理することから、
Surrogateパターンあるいは、Wrapperパターンとも呼ばれます。


Proxyパターンの特徴

Proxyパターンは、実装方法の実体(RealSubject)を利用者から隠蔽するという性質を持ちます。
共通のインターフェイス(Subject)を実装したProxyおよびRealSubjectは、
同じメソッドや同じプロパティを持つが、利用者は常に代理であるProxyに対して処理を要求します。
Proxyは必要に応じて、実体処理の都合なども考慮し、 RealSubjectに要求を出します。
つまり、利用者には分からないように、RealSubjectに対する処理の呼び出し方を調整することができます。


RealSubjectへの要求への間にProxyを挟むことで、
ネットワークでいうところのProxyサーバのように、対象オブジェクトの呼び出しのタイミングを変えたり、
保持しているキャッシュを返したりして、対象オブジェクトの代わりを果たします。
たとえば、RealSubjectの生成にコストを要する場合や、呼び出し方に注意が必要な場合に、
その調整役として、代理人であるProxyに処理を委譲します。
つまり、Proxyパターンというのは、「本人であるRealSubjectには、コストがかかったり複雑な処理は、
出来る限り考えさせないようにしましょうよ」という考え方を基本とするパターンです。
呼び出し側は、Proxyであることを意識する必要なく、RealSubjectに要求を出すときとなんら変わりません。


GoFデザインパターンの1つであるDecoratorパターンは、
Proxyパターンと似た形式で実装されるパターンの1つだが、両者は目的が異なる。
Decoratorパターンが利用者に、機能追加を提供する。それにに対して、
Proxyパターンは利用者への見せ方は変えずに、実装上の処理実体の呼び出し方を最適に調整する。


Proxyパターンの種類

GoF本では、実用でのProxyパターンの使われ方として、4種類のパターンを紹介している。

remote proxy


別アドレスにあるオブジェクトに対してのアクセスを提供するタイプのProxy。
つまり、これはプロセス間通信を実現します。
本物のオブジェクトがネットワーク越しか別プロセスにあるため、
代理オブジェクトに本物のオブジェクトとの通信を任せて、
あたかも本物のオブジェクトのように振舞わせる考え方。

virtual proxy


コストのかかるオブジェクトの作成を出来る限り先送りするタイプのProxy。
例えば、テキストと画像を読み込んで表示するような場合。
コストのかかる画像の読み込みを先送りにし、先にテキストデータを読み込んで、
テキスト表示の終了後に、画像の読み込みを行うといったようなケースが、それにあたる。

protection proxy


オブジェクトへのアクセスを制御するタイプのProxy。
オブジェクトに応じてアクセス権を変更したいような場合に有効である。
これは、しばしばvirtual proxyと併用される。

smart reference


C++などで通称スマートポインタと呼ばれているタイプのProxy。
参照されなくなった実オブジェクトを自動的に開放することを実現するために、
実オブジェクトへの参照回数を記憶しておこうというもの。
あるいは、永続オブジェクトがはじめて参照されたときに、それをメモリにロードするなどを実現する。


ProxyオブジェクトはRealSubjectの型について、常に知っている必要はない
Proxyクラスが、RealSubjectオブジェクトを抽象インターフェイスを通してのみ扱うことができるのであれば、
各RealSubjectクラスごとにProxyクラスを作る必要はない。


しかし、ProxyクラスがRaalSubjectクラスをインスタンス化する場合(たとえばvirtual proxyのように)は、
Proxyクラスは、その具象クラスを知っていなければならない、当たり前だけど。
ただ、少し応用してGoFのAbstractFactoryパターンの考え方を併用することで、
Proxyクラスが、RealSubjectのことを知る必要をなくすこともできる。



面倒くさかったけど作ったオマケ
Proxyパターン - VB.NET(C#) - 雑なサンプルソース右クリック保存