倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

Groovy で Immutable パターン

増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編』に載っているデザインパターンを Groovy/GPars で書こうシリーズ、の続き。 今回は Immutable パターン。 状態が変わらないオブジェクトは、いつどのようにスレッドからアクセスされても大丈夫!ってパターン。 状態が変わらないオブジェクトは不変(不可変 immutable)と言いますね。 Immutable なクラスは使うのは簡単ですが、作るのには結構注意がいります・・・ Java では。 Groovy では @Immutable アノテーションを使えば簡単に実装できます。 注意事項がないわけではないですが。 詳しくは「Immutable AST Macro」参照。

参考 URL

サンプル・コード


作成するソースは

  • Immutable な Person クラス
  • 実行スクリプト

です。

Person クラス

Immutable なクラスは @Immutable アノテーションを付加するだけで OK:

import groovy.transform.Immutable

@Immutable
class Person {
    String name, address
}

これで getter メソッドや equals() メソッドなどが自動で生成されます。 setter メソッドは生成されません。 コンストラクタは Map を引数にとるものが自動生成されます*1

実行スクリプト

これを使用するコードは、正直つまらないですが以下のようになります。

def alice = new Person(name:'Alice', address:'Alaska')
3.times{
    // Person を表示し続けるスレッドを作成・開始
    Thread.start printPerson(alice)
}

/** スレッドで実行する処理を書いたクロージャを返す */
def printPerson(Person person){
    return {
        while(true){
            println "${Thread.currentThread().name} prints $person"    // Person#toString() 使用
        }
    }
}

各スレッドは Person クラスの toString() メソッドを呼び出しますが、Person オブジェクトは状態が変わらないので toString() メソッドを synchronized にしたりしなくてもキチンと動作します。

追記


実行スクリプトを Actor で書くとこんな感じでしょうか:

import groovyx.gpars.actor.Actors

def alice = new Person(name:'Alice', address:'Alaska')
def actors = []
3.times{
    actors << Actors.actor{
        loop {
            println "${Thread.currentThread().name} prints $alice"
        }
    }
}
actors*.join()    // 3つの Actor オブジェクトに対して join() メソッドを呼び出す

最後の行は、3つの Actor オブジェクト(リスト actors に格納されている)に対して join() メソッドを呼び出しています。 これを行わないとすぐにスクリプトの実行が終了してしまいます。

増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編

増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編


プログラミングGROOVY

プログラミングGROOVY

*1:タプル (tuple) を引数にとるコンストラクタも生成されるようです。