前回まではメタクラスによってメソッド(クロージャ型のプロパティ)を追加してましたが、今回はカテゴリ & use キーワードで使い方を簡便化できるようにします(一覧, Jar)。
カテゴリメソッドと use キーワード
Groovy でのカテゴリ(カテゴリメソッド)とは単なる static メソッドで、use キーワードによってインスタンスメソッドのように扱えます。 例えば以下のように ComplexCategory を定義したとします:
import org.apache.commons.math.complex.Complex class ComplexCategory{ static def Complex plus(Complex c1, Complex c2){ return c1.add(c2) } }
このとき、以下のように plus() メソッドをインスタンスメソッドのように扱うことができます:
def c1 = new Complex(1d, 2d) def c2 = new Complex(3d, 4d) use(ComplexCategory){ def c = c1.plus(c2) // def c = ComplexCategory.plus(c1, c2) と同じ assert c == new Complex(4d, 6d) assert c1 + c2 == new Complex(4d, 6d) // 演算子オーバーロードも使える }
メソッドが呼び出されているオブジェクトが、実際には static メソッドの第1引数になります。
FieldCategory クラス
では、以下で FieldElement オブジェクトを使いやすくするカテゴリを定義してみましょう。 定義するのは
- 和演算、積演算に関する単位元 (0, 1) と等しいかどうかを評価する izZero(), isOne() メソッド
- 四則演算を行う plus(), minus(), multiply(), div() メソッド
です。 定義はこんな感じ:
import org.apache.commons.math.FieldElement class FieldCategory { static def boolean isZero(FieldElement<?> f){ return f.getField().getZero() == f } static def boolean isOne(FieldElement<?> f){ return f.getField().getOne() == f } // Groovy の演算子オーバーロード // + : plus static def <F extends FieldElement<F>> F plus(F f1, F f2){ return f1.add(f2) } // - : minus static def <F extends FieldElement<F>> F minus(F f1, F f2){ return f1.subtract(f2) } // * : multiply static def <F extends FieldElement<F>> F multiply(F f1, F f2){ return f1.multiply(f2) } // / : div static def <F extends FieldElement<F>> F div(F f1, F f2){ return f1.divide(f2) } }
四則演算を行うメソッドはジェネリックなメソッドにすると定義がややこしく見えますが、使い方は簡単。 また、Groovy の演算子オーバーロード機能によって、それぞれ +, -, *, / 演算子による式として実行できます:
@GrabResolver('http://www5.ocn.ne.jp/~coast/repo/') @Grab('org.waman.math:wamans-math:0.0.1') import org.waman.math.FieldCategory import org.apache.commons.math.complex.Complex def c0 = new Complex(0d, 0d) // 0 def c1 = new Complex(1d, 0d) // 1 def c2 = new Complex(1d, 2d) // 1+2i def c3 = new Complex(3d, 4d) // 3+4i use(FieldCategory){ // 零元、単位元の確認 assert c0.isZero() assert !c1.isZero() assert !c0.isOne() assert c1.isOne() // 加減乗除演算 assert c2 + c3 == new Complex(4d, 6d) assert c2 - c3 == new Complex(-2d, -2d) assert c2 * c3 == new Complex(-5d, 10d) assert c2 / c3 == new Complex(0.44d, 0.08d) }
カテゴリメソッドは static メソッドとしてしか定義できないのでちょっと融通が利かないところもありますが、メタクラスによるクラスの追加よりは簡単に使えますね。
入門Common Lisp―関数型4つの特徴とλ(ラムダ)計算
- 作者: 新納浩幸
- 出版社/メーカー: 毎日コミュニケーションズ
- 発売日: 2006/09
- メディア: 単行本
- 購入: 2人 クリック: 51回
- この商品を含むブログ (46件) を見る
- 作者: 奥村晴彦,杉浦方紀,津留和生,首藤一幸,土村展之
- 出版社/メーカー: 技術評論社
- 発売日: 2003/05
- メディア: 単行本
- 購入: 2人 クリック: 44回
- この商品を含むブログ (58件) を見る