読者です 読者をやめる 読者になる 読者になる

No Programming, No Life

新しいNPNLです。http://d.hatena.ne.jp/fumokmm/ から引っ越してきました。

Groovyで@Categoryを使ってカテゴリクラスを作成する

@Categoryアノテーションを付けるとそのクラスをカテゴリクラスにできますよというサンプル。この機能はObjective-Cのカテゴリ由来のようです*1
以前までは第一引数にメソッドを追加したい型をパラメータself*2として付けたstaticなメソッドを宣言してやる必要がありましたが、@Categoryアノテーションを付ければAST変換してくれて簡単にカテゴリクラスの出来上がりという寸法です。いやー便利便利。

@Category(メソッドを追加したい型)
class Hoge {
  // 通常のメソッド宣言
}

という形式です。

カテゴリってstaticメソッドは追加する方法はないのかなーと思ってTwitterでつぶやいてみたら@nobeansさんがサクっと教えて下さいました、素敵すぎる。感謝致します*3

.@fumokmm 強引ですけどこんなのはどうでしょ。つ https://gist.github.com/950540Sun May 01 14:34:40 via YoruFukurou

ということで、例としてjava.util.Dateクラスにstaticメソッドとしてnow()っていう現在のDateを返却するメソッドを追加することを考えます。

昔ながらのカテゴリクラス

class DateStaticCategoryOld {
  static Date now(Class<Date> self) {
    if (! self?.isAssignableFrom(Date)) {
      throw new ClassCastException('java.util.Date only.')
    }
    new Date()
  }
}

@Categoryを使った方

@Category(Class)
class DateStaticCategory {
  Date now() {
    if (! this.isAssignableFrom(Date)) {
      throw new ClassCastException('java.util.Date only.')
    }
    new Date()
  }
}

Classクラスをパラメータと指定しているため、違うクラスにuseした場合も使えてしまうので、その場合はClassCastExceptionを投げるようにしています。

使うときは、

use(Hoge) {
  // ここのブロック内(クロージャ内)では
  // Hogeで宣言されたメソッドが利用可能
}

とします。
カテゴリクラスを複数使いたい場合は、

use(Hoge, Fuga, ...) {
  // ...
}

とします。

staticメソッドとinstanceメソッドを同時に追加してuseする例

リポジトリ

この機能を使ったGroovyライブラリ拡張を書いてます。*4
404 · GitHub

*1:2011-05-02 追記。

*2:変数名はselfじゃなくてよく、自由です。

*3:2011-05-02 追記。

*4:2011-05-03 追記。