taediumの日記

2013-08-11

[][] ドメインクラスで型パラメータをサポート

@

さんの発言から。



いいですね!

さっそく実装してSNAPSHOTつくってみました。


ぜひお試しください。ブラッシュアップして次のバージョン(1.32.0)で正式リリースに組み込みたいと考えています。


使用例


使用例を示します。


以下のようにドメインクラスに任意の数の型パラメータを指定できます。ここでは1個だけですが、何個でもOK。

@Domain(valueType = int.class)
public class Weight<T> {

    private final int value;

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

    public int getValue() {
        return value;
    }

    public Weight<T> add(Weight<T> other) {
        return new Weight<T>(value + other.value);
    }
}

利用する側では次のように実型引数に具体的な型を指定します(ワイルドカードや型変数の使用はサポートしていません)。

@Entity
public class Person {

    public Weight<kg> weight;
}
@Entity
public class Food {

    public Weight<g> weight;
}

上の例では、単位を表すkgやgという型を作って型引数にしました。

public interface kg {}
public interface g {}

これでいったい何がうれしいかというと、Weight<kg>とWeight<g>は別の型なので安全性を高められるということです。

つまり、次のようなコードはコンパイルできません。

Person person = ...
Food food = ...
Weight<kg> weight = person.weight.add(food.weight);

Domainでファクトリメソッドを使うには ?


上の使用例では、Domainクラスをコンストラクタでインスタンス化しています。

ファクトリメソッドが好きな人もいるでしょう。

ファクトリメソッドでは、クラスの型変数宣言と同等の宣言をしてください。

この例では、ofメソッドがファクトリメソッドです。

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

    private final int value;

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

    public int getValue() {
        return value;
    }

    public Weight<T> add(Weight<T> other) {
        return new Weight<T>(value + other.value);
    }

    public static <T> Weight<T> of(int value) {
        return new Weight<T>(value);
    }
}

ExternalDomainを使うには ?


ValueObjectにアノテーションをつけたくない(つけられない)場合のために、ExternalDomainという機能がありますが、こちらでも型パラメータに対応しています。

注意点は1つです。

  • DomainConverterの実装では、Domainクラスはワイルドカードを使って扱ってください。

これがValueObject。上の例と違ってアノテーションついていません。

public class Weight<T> {

    private final int value;

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

    public int getValue() {
        return value;
    }

    public Weight<T> add(Weight<T> other) {
        return new Weight<T>(value + other.value);
    }
}

これが、ValueObjectと基本的な値を相互変換するコンバーター(DomainConverterの実装)。Weightの型引数に?(ワイルドカード)を指定しています。

@ExternalDomain
public class WeightConverter implements DomainConverter<Weight<?>, Integer> {

    @Override
    public Integer fromDomainToValue(Weight<?> domain) {
        ...
    }

    @Override
    public Weight<?> fromValueToDomain(Integer value) {
        ...
    }
}

backpaper0backpaper0 2013/08/11 20:19 こそっとつぶやいただけのアイデアを取り込んでくださってありがとうございます!
早速試してみました。ID<Emp>などを実現できて嬉しいです!

taediumtaedium 2013/08/12 13:01 いえ、こちらこそナイスアイデアありがとうございました。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/taedium/20130811/p1