Proxyパターンは、クライアントが直接扱うには不都合があったり困難が生じるようなターゲットをクライアントのかわりに操作する方法である。クライアントはProxyを通じてターゲットの操作を行う。Proxyパターンでは実際のターゲットとProxyの区別がつかない工夫がされており、そのためクライアントはProxyを実際のターゲットと同一のものとして扱うことができる。Proxyパターンを導入することで生じる負荷がクライアントには一切かからないというのが利点だろう。
Proxyパターンは利用用途の幅が広く様々なバリエーションがある。 ここでは代表的なもの二種類についてのみ解説する。
例えばサイズの大きい画像があったとしよう。 アプリケーション起動時に、この画像サイズに合ったスペースをレイアウトに組み込みたかったとする。 しかしアプリケーションの起動と同時に大きい画像ファイルを読み込み、 その結果起動動作が鈍くなるという状況は避けたいだろう。 そこで、実際の画像のかわりになるProxyを作成し、 アプリケーション起動時にはProxyを使って画像スペースを確保する。 実際の画像の表示はクライアントから指示があった時点でProxyオブジェクトが代行する。 こうすることで、画像を読み込むという大掛かりなプロセスを先送りにすることができる。
異なる二つのアプリケーションがあったとする。 例えばアプリケーションAからアプリケーションB内のオブジェクトを操作する場合を考えよう。 AとBは異なるアプリケーションのため、それぞれが使用しているメモリ領域も異なる。 そのため異なるアプリケーション間のオブジェクト参照は 同一アプリケーション内のオブジェクト参照よりもプロセスは複雑になることが予想される。 そこでアプリケーションBのオブジェクトのProxyをアプリケーションAに導入し、 実際のアプリケーション間通信作業をProxy内に押し込めてしまう。 こうすることで、アプリケーションAはアプリケーションBに存在するオブジェクトを 自分が保有するオブジェクトのように扱うことができる。
以下の例では、画像クラス(Image.as)の遅延ロードにProxyパターンを採用している。 アプリケーション起動時に画像サイズにしたがったレイアウト処理(ステージ中心に画像を配置)を施したいが、 サイズを取得するために実際の画像をロードするということは回避したいという状況である(上記Virtual proxy参照)。 そこでアプリケーション起動時には画像クラスのProxy(ImageProxy.as)を用いて (画像サイズが既知であるという前提があるが)画像のサイズ情報を取得している。 アプリケーション起動後、マウスクリックにより実際の画像がロードされる。
//main.as package { import flash.display.Sprite; import flash.events.MouseEvent; import proxy.Image; import proxy.ImageProxy; [SWF(width="1000",height="1000")] public class main extends Sprite{ private static const STAGE_WIDTH:int = 1000; private static const STAGE_HEIGHT:int = 1000; protected var _proxy:ImageProxy; public function main(){ _proxy = new ImageProxy(); _proxy.x = (STAGE_WIDTH - _proxy.width)/2; _proxy.y = (STAGE_HEIGHT - _proxy.height)/2; this.addChild(_proxy); stage.addEventListener(MouseEvent.CLICK, onClick); } /** * @private */ private function onClick(e:MouseEvent):void{ _proxy.load(); e.target.removeEventListener(MouseEvent.CLICK, onClick); } } }
//Image.as package proxy{ import flash.display.Bitmap; //Image size of 800x600 [Embed(source="assets/large.jpg")] public class Image extends Bitmap{ } }
//ImageProxy.as (Proxy) package proxy{ import flash.display.Sprite; public class ImageProxy extends Sprite{ private static const IMAGE_WIDTH:int = 800; private static const IMAGE_HEIGHT:int = 600; /** * Constructor */ public function ImageProxy(){ } public function load():void{ this.addChild(new Image()); } override public function get width():Number{ return IMAGE_WIDTH; } override public function get height():Number{ return IMAGE_HEIGHT; } } }