JavaとRubyの動的プロキシ

最近、Rubyを仕事で使いそうな気配があるため、メタプログラミングRubyを呼んでいる。

メタプログラミングRuby

メタプログラミングRuby

私は、Rubyを使うことの意義の一つとして、Javaと比較してメタプログラミングが簡易・柔軟に出来ること、又、それを活用したツール(RailsRSpec等)が充実していることだと思っている。

今回は、その中で動的プロキシを両言語で比較する。

動的プロキシとは

プロキシパターンとは、何らかのオブジェクトのインタフェースを実装したプロキシオブジェクトを利用し、そのプロキシから実際のオブジェクトのメソッドを呼び出すことで、メソッド実行の前後に処理を追加したりする物である。AOPが利用可能なフレームワーク等はこの機構を利用して機能を実現している。

動的プロキシとは、このプロキシオブジェクトを動的に生成する仕組みである。 ※ちなみにこれはJavaの話、Rubyではインタフェースを使用しないため、プロキシオブジェクトは使用しない。

動的プロキシで実現できること

動的プロキシでは以下の様な事が実現出来る

  • 既存のメソッドに対する処理の追加
  • 既存のオブジェクトに対するメソッド、プロパティの追加

両言語では、以下の様な対応となる

Java Ruby
処理の追加
メソッド、プロパティの追加

Javaでは、java.lang.reflect.Proxyクラス、cglib等のライブラリを利用して処理の追加は可能だが、メソッド、プロパティを追加することは出来ない。 しかし、Rubyでは後者が可能になっている。

Rubyにおける動的プロキシ

Rubyで、動的プロキシを実現する方法として、method_missingを利用する方法がある。

RubyJavaとは違い、実行時にメソッドを解決し、見つかったメソッドを呼び出す。対応するメソッドが存在しない場合には、BasicObject#method_missing(private)メソッドが呼び出される(Javaで言うところの,reflection使用時のNoSuchMethodException)。

全てのオブジェクトはBasicObjectを継承しているため、method_missingをオーバライドすることで、存在しないメソッドを呼び出すことが出来るわけである。

本では、FlickerのRubyライブラリの以下のコードを例にしている。

class Flickr
  def request(method, *params)
    #Flickrへのリクエスト処理
    #Flickrではリクエストパラメータのmethodで、処理を決定する。
    # 例)http://.../?method=flickr.people.findByUsername
    ...
  end 

  def method_missing(method_id, *params)
    #method_idはメソッドのシンボル、*paramsは配列引数.
    #flickr.people_findByUsername => flickr.perople.findByUsername へと変換される
    request(method_id.id2name.gsub(/_/, '.'), params[0])
  end
  
  ...

まとめ

Rubyのメタプログラミングはかなり協力でかなり使えるので、ガンガン使っていきたい! しかし、簡単に機能が拡張でき過ぎる麺もあるので、ある程度の規模の案件などで利用する場合は規約で縛ることがもちろん重要ですね。