uehaj's blog

Grな日々 - GroovyとかGrailsとかElmとかRustとかHaskellとかReactとかFregeとかJavaとか -

Expando MetaClassとは何か

Groovyでは動的にメソッドを付け足したりする方法がいくつかある。MetaClassは従来からあるそのような仕組みの一つである。しかし、従来はinvokeMethodをオーバーライドしたりする必要があり、面倒であった。これをExpandoのように、つまりマップの様に簡単にメソッドやフィールドを追加定義できるようにしたものがExpando MetaClass。

なお、「Expando」だけでも動的にメソッドを付け足すことができるが、あらかじめExpandoであるものだけ、かつ特定インスタンスにだけしか注入できないことに注意。つまり、ある「クラス」に対するインスタンスすべてに対してメソッドを追加定義することはできないし、既存のクラス(例えばString)などに追加することもできない。MetaClassレベルに追加できるためにはExpand MetaClassが必要となる。

assert String.metaClass.class == ExpandoMetaClass
String.metaClass.camelize = {
 delegate.tokenize().collect{it.getAt(0).toUpperCase()+it.getAt(1..-1)}.join()
}

assert "hoge hoge".camelize() == "HogeHoge"

てな感じでしょうか。なお、単に上の様にするだけでは特定クラスに対するメソッド追加にしかならず、サブクラスについても追加したい(呼び出せるようにしたい)場合はExpandoMetaClass#enableGlobally()を呼んどく必要がある。こいつはExpandoMetaclassによって動的追加されたメソッドに対する探索ポリシーを変更するもので、パフォーマンスに多大な影響を及ぼすのでお勧めできない(小細工やデモでするならともかく、実用的には、継承階層まで影響を及ぼしたいメソッド追加ならCategory(use)とかで追加したほうがいい)。