その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

Groovyで動的にメソッドを生やす

インスタンスにメソッドを生やす

class EmptyCat {}
def cat = new EmptyCat()
cat.metaClass.nyan = { return 'meow' }
cat.nyan() // => 'meow'

インスタンスmetaClass からMetaClass (HandleMetaClass) を引っ張ってきて,それ経由で生やしたいメソッドの名前を指定し,Closureを代入してやると良い.

インスタンスメソッドとして生やす

上記がインスタンス自体にメソッドを生やしていたのに対し,こちらはクラスに対してメソッド追加の処理を行い,そのクラスがinstantiateされた際にそのメソッドを利用可能にするという方法.

class EmptyHuman {}
EmptyHuman.metaClass.greet = { return '無……' }
def human = new EmptyHuman()
human.greet() // => '無……'

クラスの metaClass からMetaClass (ExpandoMetaClass) を引っ張ってきて,それ経由で生やしたいメソッドの名前を指定し,Closureを代入してやると良い.

クラスメソッドとして生やす

class EmptyDog {}
EmptyDog.metaClass.static.wan = { return 'bow' }
EmptyDog.wan() // => 'bow'

クラスの metaClass.static からMetaClass (ExpandoMetaClass) を引っ張ってきて,それ経由で生やしたいメソッドの名前を指定し,Closureを代入してやると良い.

所感

Groovyらしい機能という感じ.finalなインスタンスであろうとfinalなクラスであろうとこのような機能を実現することができ,脱出ハッチが用意されているという謎の安心感はある.
こうした広義のメタプログラミングが簡単にできるのは便利である一方で,使う場所を誤るあるいは多用しすぎると途端にコードが魔界と化す予感がある (これはメタプログラミング全般に言えることです).節度を持った利用を心がける必要がありそうだが,しかしこういう処理を容易に書けるように言語側がアフォードするのは中々男らしい,という感想です.