GoF本 Proxy

GoFデザインパターン勉強メモ

ねらい

  • あるオブジェクトの代理やプレースホルダを提供し、アクセス制御を実現する

AKA

  • Surrogate

モチベーション

  • ドキュメントエディタ上の画像オブジェクトの例

    • 画像はコスト高い
    • 最初から全部は見えてないので、最初に全部読み込む必要はない
    • 見えるようになってから読み込めばいい
  • 画像を遅延初期化することにより・描画・テキスト成形のロジックに影響が及ぶべきではない
  • 画像のプロキシImageProxyを導入することで解決する

    • 利用側からは画像オブジェクトと区別がつかない(同じインターフェース)
    • 画像オブジェクトの初期化の責務を担う
    • 幅高さ情報ももつ

      • 画像オブジェクト読み込み前はとりあえず0とかを返す
      • 読み込み後は、画像の幅高さを返す

つかいどころ

Remote Proxy

  • 異なるアドレス空間のオブジェクトを仲介するプロキシ
  • Ambassador (大使)とも

    • 国境をまたぐイメージからか

Virtual Proxy

  • 遅延生成・遅延初期化を行うプロキシ

Protection Proxy

  • アクセス制御を行うプロキシ

Smart Reference

  • 裸のポインタを置き換えるもの
    • std::shared_ptr<T>

      • 参照カウント、0になったら解放
    • 永続データのアクセサ (DAO: Data Access Object)
    • 排他制御つきのアクセサ

      • なんか名前あるんだろうか

登場人物

  • Proxy

    • RealSubjectへの参照を保持する
    • RealSubjectSubjectとのインタフェースが一致していれば
      (= RealSubjectのインタフェースがSubjectのスーパーセットでなければ)
      Subjectへの参照を保持することもある
    • Subjectインタフェースを実装する

      • RealSubjectと置換できるよう
    • RealSubjectへのアクセス制御や、生成・初期化・解放の責務を負う
    • 種類別の責務

      • Remote Proxy

        • 異なるアドレス空間に要求を仲介する

          • リクエストや引数の変換等を伴う
      • Virtual Proxy

        • RealSubjectオブジェクトの生成を遅延させられるよう、
          追加の情報をもつことがある

          • ImageProxyの幅高さ0、など
      • Protection Proxy

        • 呼び元の認可
  • Subject

    • RealSubjectProxyに共通のインタフェースを与える
  • RealSubject

    • Proxyが代理をつとめる対象のオブジェクトのクラス

クライアントコードからの利用

  • クライアントコードはSubjectに対して操作を行う
  • Proxyはこれを受け取り、RealSubjectに良しなに仲介する

    • 「良しなに」はProxyの種類によりけり

結果

  • 中間層が1つ追加されることにより・・・

    • Remote Proxy

      • オブジェクトが別のアドレス空間にあることを隠蔽できる
    • Virtual Proxy

      • 遅延生成・遅延初期化できる
    • Protection Proxy/Smart Reference

      • オブジェクトアクセスの前後でなんかできる

        • アクセス拒否
        • 参照カウント

          • カウント0でオブジェクト解体・メモリ解放
  • copy-on-write

    • 巨大なオブジェクトのコピーで有用
    • 実際にコピーが必要になるまで、複製処理を遅延する

      • modificationが生じないかぎり不必要
    • Virtual ProxyとSmart Referenceとの合わせ技といえるかも

実装にあたり考えるべきこと

言語の機能を使うと幸せになれることも

演算子オーバーロード

  • C++の->とか*とか

    • Virtual Proxyなんかで有用
    • Protection Proxyのように、一部の操作のみRealSubjectに取り次ぎたいような場合には不適切

マジックメソッド(って一般的なワードなんだろうか)

  • 未定義のメソッドが呼び出されたときに呼ばれるやつ

    • SmalltalkのdoesNotUnderstand:
    • PHPの__call()
  • doesNotUnderstand:の弱点

    • 言語組み込みの一部の操作については呼ばれない

      • ==演算子とか
    • もともと例外処理用であり、速度が遅い
  • 無限再帰に注意する

Proxyが包むオブジェクトの型

  • RealSubjectSubject派生なので、インタフェースはスーパーセットになる
  • インタフェースが一致していれば、ProxySubjectを集約してもいい

    • すべてのRealSubjectProxyでさえも一様に扱える
  • Virtual Proxy等、特定のRealSubjectをインスタンシエートしなければならない場合は、その具象クラスのオブジェクトを集約する

関連するパターン

  • Adapterとの対比

    • Adapterは、Adapteeと異なるインタフェースを提供する
    • Proxyは、基本的にRealSubjectと同じインターフェースを提供するが、
      Protection Proxyはこの限りではない

      • 操作を認可しない場合、インタフェースはサブセットになる
  • Decorator

    • 実装は似ているが目的が異なる

      • Decorator: インタフェースをそのままに、オブジェクトに責務を追加する
      • Proxy: オブジェクトのアクセス制御を行う
    • 【所感】というか集約のパターンの実装はどれも似たり寄ったりだと思う
    • Proxyの種類によっては、実装が似通わなくなるケースもある

      • Remote Proxy

        • オブジェクトそのものの参照はもたず、間接的な参照をもつ

          • 「ホストIDとローカルアドレス」とか
      • Virtual Proxy

        • 最初はオブジェクトそのものの参照はもたず、間接的な参照をもつ

          • ファイル名とか

英語

  • Ambassador

    • 大使

      • 国をまたぐ代理人、というかんじ
      • こういう比喩すき
  • Housekeeping

    • 【計算機】後始末処理

      • Dispose()とか