DPDesign Pattern Quest
#12 / 23
S構造DIFF

プロキシ

Proxy

本人の代わりに受付が立つ。アポ取り・身分確認・取次ぎを代行して、本人は本来の仕事に集中。

Intent · 目的

本物のオブジェクトの代理として、同じ顔つき(インタフェース)で振る舞うラッパー。本物に到達する手前で、認可・遅延読込・キャッシュ・ログ・リモート呼び出しなどを差し挟める。

Motivation · 動機

「画像を100枚並べたいけど、ページを開いた瞬間に全部読み込んだら重い」── スクロールして見えた瞬間にだけ読みたい。本物の `Image` クラスにその機能を持たせると責務が肥大化する。代わりに、同じ顔をした『代理画像』を100枚置いておき、表示要求が来た瞬間に内部で本物を呼ぶ。利用側は『代理だ』と意識する必要がない。受付係が「ちょっとお待ちを」と言ってる間に、本物に取り次いでくれている、そんなイメージ。

適用場面

  • 1リモートオブジェクトをローカルのように扱いたい(リモートプロキシ)。
  • 2重いオブジェクトの初期化を遅延したい(仮想プロキシ/Lazy load)。
  • 3アクセス制御・認可を差し込みたい(保護プロキシ)。
  • 4結果のキャッシュ、ロギング、計測を透過的に差し込みたい。

概念図

サンプルコード

interface Image { display(): void; }

class HighResImage implements Image {
  constructor(private path: string){ console.log(`loading ${path}...`); }
  display(){ console.log(`show ${this.path}`); }
}

class ImageProxy implements Image {
  private real: HighResImage | null = null;
  constructor(private path: string) {}
  display(){
    if (!this.real) this.real = new HighResImage(this.path);
    this.real.display();
  }
}

const img: Image = new ImageProxy("photo.jpg");
img.display();
Pros · メリット
  • 本物に手を入れずに、振る舞いを差し挟める。本人の集中を邪魔しない受付係スタイル。
  • 用途が幅広い:遅延読込、認可、キャッシュ、ログ、計測、リモート呼出し。
  • クライアントから見れば本物と同じ顔。途中差し替えも容易。
Cons · デメリット
  • 間接層が増えてデバッグが面倒に。スタックを覗くと『プロキシまみれ』になることも。
  • 受付の権限がどんどん増えると、いつの間にか神オブジェクト化する。
  • リモートプロキシは透過的すぎて、クライアントが『これがネットワーク呼出しだと知らずに』連発し、レイテンシ事故を起こす。

関連パターン

⚔ ready to test

理解度を確かめる時間だ

3 問のクイズで、 このパターンを身体に染み込ませよう。

挑戦する →