KnowHow

技術的なメモを中心にまとめます。
検索にて調べることができます。

Python基礎 オブジェクト指向15(Proxy) 構造に関するデザインパターン

登録日 :2025/10/14 07:07
カテゴリ :Python基礎

Proxy

代理となるオブジェクトを通じて、間接的に目的のオブジェクトにアクセスさせるためのパターン

  • 目的のオブジェクトへのアクセスを制御し、目的のオブジェクトへのリクエストが届く前後に別の処理を行うことができるようにする(ログ出力など)
    例)プロキシサーバ

構成要素

Subject

  • 抽象クラスまたはインターフェース
  • 目的のオブジェクトで提供する機能のAPIを定義

RealSubject

  • Subjectを継承(実装)する子クラス
  • 目的の機能を提供する「本人」となるクラス

Proxy

  • Subjectをを継承(実装)する子クラス
  • 目的のオブジェクトの代理人となるクラス
  • 内部に目的の「本人」オブジェクトを保持しており、必要に応じて「本人」の機能を呼び出す

オブジェクト指向的要素

「ポリモーフィズム」と「委譲」を利用したパターン

  • RealSubjectとProxyは同じSubjectインターフェースを実装
  • クライアントはインターフェースのAPIを介してアクセスすることで、その違いを意識する必要がない
  • Proxyは属性のRealSubjectに処理を委譲する

メリット・デメリット

メリット

  • オブジェクトへのアクセスが間接的になる
  • 目的のオブジェクトがまだ存在しない場合でも開発が進められる
  • 容易に新規プロキシの追加が可能

デメリット

  • 新しいクラスをつかする必要があるため、コードがより複雑になる可能性がある

使い所

リクエストの前後に処理を追加したい場合

  • ロギング
  • キャッシュ

目的のオブジェクトに対してアクセス制御を行いたい場合

サンプルコード

サーバリクエストのロギングとアクセス制御

from abc import ABCMeta, abstractmethod


class Server(metaclass=ABCMeta):
    @abstractmethod
    def handle(self, _user_id: str):
        pass


class RealServer(Server):
    def handle(self, _user_id: str):
        print(f"[INFO] Server: {_user_id}の処理を実行中")


class Proxy(Server):
    def __init__(self, _server: Server):
        self.__server = _server

    @staticmethod
    def _authorize(_user_id: str):
        authorized_user_id = ["1", "2", "3"]

        if _user_id not in authorized_user_id:
            raise Exception("[ERROR] Proxy :操作が許可されていません")

    def handle(self, _user_id: str):
        self._authorize(_user_id)
        print("[INFO] Proxy: 処理を開始します")
        self.__server.handle(_user_id)
        print("[INFO} Proxy: 処理が終了しました")


def execute(_user_id: str):
    server = RealServer()
    proxy = Proxy(server)

    try:
        proxy.handle(_user_id)
    except Exception as e:
        print(e)
    finally:
        print('--- fin ---')


if __name__ == '__main__':
    execute("1")
    execute("5")