Doma 1.12.0 で可能になったドメインクラスのファクトリメソッドの使いどころ

ドメインクラス(http://doma.seasar.org/reference/domain.html)は、これまで直接コンストラクタを呼び出すことでしか生成できなかったのですが、staticなファクトリメソッドを介して生成できるようになりました。ファクトリメソッドをアプリから呼び出せることはもちろん、DomaがDBから値を取得しオブジェクトを生成するときもファクトリメソッド経由にできます。

使い方は簡単。@DomainのfactoryMethod要素にファクトリメソッドの名前を指定します。たとえば、年齢を表すAgeクラスのファクトリメソッドを「of」とする場合、次のように記述します。

@Domain(valueType = int.class, factoryMethod = "of")
public class Age {

    private final int value;

    // ファクトリメソッドを使った生成をクライアントに強制する場合はコンストラクタをprivateにする
    private Age(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    // 必要に応じてキャッシュされた値を返すファクトリメソッド
    public static Age of(int value) {
        if (0 <= value && value < 100) {
            return AgeCache.cache[value];
        }
        return new Age(value);
    }

    private static class AgeCache {
        static Age cache[];
        // ...
    }
}

これは、ファクトリメソッドでキャッシュされた値を使う例です。


特定の値について振る舞いを変えたいときには、サブクラスを返すこともできます。

@Domain(valueType = int.class, factoryMethod = "of")
public class Weight {

    protected final int value;

    private Weight(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    // 値に依存する振る舞い
    public int calculateSomething() {
        // ...
    }

    // 軽い場合は特別な処理をするためサブクラスのインスタンスを返す
    public static Weight of(int value) {
        if (value < 1000) {
            return new LightWeight(value);
        }
        return new Weight(value);
    }

    private static class LightWeight extends Weight {
        protected LightWeight(int value) {
            super(value);
        }

        @Override
        public int calculateSomething() {
            // ...
        }
    }

}

staticなファクトリメソッドの利点についてはEffective Java 第2版 (The Java Series)に詳しい説明があるので、使いどころの参考になります。

これまでどおりコンストラクタを直接使った生成をしたい場合は@DomainにfactoryMethod要素を記述しなければOKです。