Proxy パターン for Ruby / Rails

この記事は本の感想、備忘録です。

Proxy パターン

Proxyは代理、委任という意味なので、 Proxyパターンとは、オブジェクトへのアクセスする際に代理のオブジェクトを使うようなデザインパターンです。 (by Technologic Arts | Proxyパターン

f:id:meikotan:20210223124521j:plain

Proxy の実装ポイントは RealSubject とインターフェースを同じにすることです。(透過的)

Main は実際に呼び出すのが Proxy でも RealSubject でも気にしません。RealSubject を直接利用しても、間に Proxy が入っても、問題なく使用できます。

それではなぜ Proxy を置くのでしょうか?目的は主に3つです。

オブジェクト生成の遅延(Virtual Proxy)

RealSubject のオブジェクト化コストが高い場合に有効です。RealSubject が実際に使われるまでオブジェクト化を遅延できます。

class BankAccount
  attr_reader :balance

  def initialize(starting_balance = 0)
    @balance = starting_balance
  end
end

class VirtualAccountProxy
  def initialize(&creation_block)
    @creation_block = creation_block #DI
  end

  def balance
    s = subject
    s.balance
  end

  def subject
    @subject || (@subject = @creation_block.call)
  end
end

account = VirtualAccountProxy.new { BankAccount.new(10) }

アクセス制限(Access Proxy)

ロキシーを使ってアクセス制御を行うと、関心事の分離を上手に行えるという利点があります。 プロキシーが気にするのは、何をすることが許されているのが誰で、許されていないのが誰なのかということです。

class AccountProtectionProxy
  def initialize(real_account, owner_name)
    @subject = real_account
    @owner_name = owner_name
  end

  def balance
    check_access
    @subject.balance
  end

  def check_access
    # ユーザ検証処理
  end
end

ロキシーにセキュリティを実装することにより、簡単にセキュリティ指針を変更したり(サブジェクトを違うプロキシーでラップする)、あるいはセキュリティを一気に取り除く(プロキシーのラップをやめる)ことができます。 それ故にセキュリティの実装に踏み込むことなく BankAccount オブジェクトの実装を変更することも可能です。

Proxy サーバ

Proxy という用語はサーバへのアクセスの踏み台として使われる Proxy サーバの方が身近かもしれません。Proxy サーバ設置の目的はネットワークセキュリティです。社内サーバやお客様サーバにアクセスするときに社内にある Proxy を経由してアクセスする仕組みになっていることが多いです。これもアクセス制限という関心事をプロキシーに分離している構造です。
f:id:meikotan:20210223123144j:plain

オブジェクトの置き場所の隠蔽(Remote Proxy)

クライアント機のプログラムからネットワーク越しの BankAccount オブジェクトにアクセスしたい場合、クライアント機にリモートプロキシーを置き、プロキシー経由で BankAccount オブジェクトにアクセスすることでネットワーク通信部分の処理をプロキシーに任せることができます。

クライアントから見ると、本物の BankAccount オブジェクト上のメソッドだと思って呼び出し、しばらくして(ひょっとすると、かなり長い時間が経った後に)返事が返ってきます。これが、全てのリモートプロシージャコール(RPC)システム動作のほとんどすべてです。

キャッシュサーバ

Web サーバの表示速度を上げるためにクライアントとサーバの間にキャッシュサーバを置くことがあります。これも同じ構造です。

Web ブラウザがある Web ページを表示するとき、いちいち遠隔地にある Web サーバにアクセスして、そのページを取得するのではなく、HTTP プロキシーがキャッシュしてあるページを代わりに取得します。最新情報が必要になったときやページの有効期限が切れたときにはじめて、Web サーバに Web ページを取りに行くのです。

RPC(リモートプロシージャコール)

この構造を知っていると複雑そうに見えていた RPC(遠隔手続き呼出し) の理解が容易になりました。

gRPC(Google RPC)は Google がプロキシの定義方法や通信方法を定めた RPC なのかな。マイクロサービスのサービス間通信でも使うし、もちろん RESTful API の代替にもなる。なるほど。
👀 トレンドマイクロ セキュリティブログ安全を保つためのgRPC実装の注意点を解説 | トレンドマイクロ セキュリティブログ

Adapter との違いは?

Adapter パターンと Proxy パターンはあるクラスをラッピングするという構造は同じですが、ラッピングするクラスが透過的であるか否かが異なります。Adapter パターンは Main が扱いやすいように Subject のインターフェースを変換するパターンです。そのため透過的とは言えません。Proxy パターンは Subject へのアクセスを何らかの形でコントロールするためのパターンで、Proxy が透過的であるが故に、そのコントロールをいつでも無効にすることが可能です。