[Groovy] Categoriesを使って既存クラスにメソッドを追加する

2020.09.11

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

Groovyにはメタプログラミング向けの特徴が多数あります。Categoriesはその特徴のひとつであり、限定された範囲で一時的に既存クラスにメソッドの追加を行うことができます。

Category Classを使う

試しに TimeCategory と呼ばれるCategory Classを使ってメソッドの追加を行ってみます。

use(TimeCategory)  {
    println 1.minute.from.now 
    println 10.hours.ago

    def someDate = new Date()       
    println someDate - 3.months
}

useメソッドは引数にCategory Classとクロージャを受け取ります。Category Classには追加したいメソッドが記述されており、以降のクロージャではそれらのメソッドが対象クラスに追加されます。

上記の例ではIntegergetMinutegetHoursDateminusなどのメソッドが追加されています(それぞれのメソッドはフィールドアクセスや演算子オーバーロードされています)。

Category Classを作る

Category Classを自作したい場合は、通常のクラスと同様に宣言し、追加したいメソッドは全てstatic methodとして実装する必要があります。またメソッドの第一引数(self)の型がメソッドの追加対象クラスを表します。

例としてStringに回文判定をするメソッドを追加するCategory Classを実装してみます。

class PalindromeCategory {
    static boolean isPalindrome(String self){
        return self == self.reverse()
    }
}

useを使って拡張すると文字列に対してisPalindromeが使えるようになります。

use(PalindromeCategory){
    assert "abcba".isParindrome() == true
    assert "nishioishin".isParindrome() == false
}

@Categoryアノテーションを使ってCategory Classを表現することもできます。この場合、アノテーションに対象クラスを指定することでメソッドの第一引数を省略することができます。またメソッドもstaticではなく通常のメソッドとして宣言できます。

@Category(String)
class PalindromeCategory {
    boolean isParindrome(){
        return this == this.reverse()
    }
}

参考