Groovyでクラスを静的に動的拡張する方法
はじめに
GroovyではExpandoMetaClassの機能を利用してメタプログラミングが可能です。これにより動的にクラスにメソッドを定義できるため豊かなプログラミングスタイルを提供できます。
しかし、GroovyにはRubyのようなincludeキーワードがないため、拡張部分をモジュール化して扱う機能が弱いと思います。Groovyスクリプトとして書く場合には先頭で拡張を込みでスクリプトを書けばよいが、そうではなくてクラスベースでGroovyを書く場合はどこに書いておけばいいのか迷うところです。
タイトルがまどろっこしいですが、やりたいことは「あるドメインではあるクラスには拡張されたメソッドがある体で動作させたい」ということを静的と表現しています。
サンプル
ということで私が普段利用している方法をひとつご紹介します。とりあえずサンプルで用意したクラスは以下のような感じです。
/root +-- Main.groovy `--/ext +-- StringExt.groovy <- Stringの拡張をここに定義 `-- FileExt.groovy <- Fileの拡張をここに定義
FileExt.groovy
解説
ポイントとなるのはstaticイニシャライザです。今回のサンプルではMain、StringExt、FileExtの中で定義しています。staticイニシャライザはクラスのロード時に読み込まれるため、まずMain.groovyの中で
static {
ext.StringExt
ext.FileExt
}
のようにクラス名のみ記述することによりStringExtとFileExtのそれぞれのクラスがロードされます。ロードされたそれぞれのクラスの中のstaticイニシャライザでmetaClassにより拡張を定義していますので、StringとFileにメソッドが拡張定義されるわけです。これによりRubyで拡張定義されたRubyファイルをincludeしたような効果が得られるようにしています。
リポジトリ
追記 (2011-04-05)
Githubにてリポジトリ管理始めました。
fumokmm/groovy-gdkpp · GitHub
追記 (2011-05-03)
当初はMOP使ってたのですが、@Categoryを使う方針に変更しました。
追記 (2011-05-05)
groovy-extensionsというリポジトリが既にあったため、リポジトリ名を変更しました。