Spring Boot/Doma/ドメインクラス

Spring Boot/Doma/ドメインクラス

Doma では値を集合させた意味ある塊としての Entity だけでなく、値それぞれに対しても意味を定義できるようになっている。

例えば人間の年齢という値なら、普通は int が割り当てられて、それを数値のように比較したり足したり引いたりしたいわけだが、年齢にはもっとほかにも性質があり、負の値は必要ないとか、200を超える値にはならないとか、そういうのがある。

そのような性質も含めクラスとして定義してその定義を組み合わせて Entity を作ればより堅牢な設計になるだろという考え方である。素晴らしいと思う。

これを全面的に用いることで、引数の順番間違えなどが起こらなくなる。

作り方

Domain アノテーションをつけて Entity のフィールドに使える基本型を指定する。

@Domain(valueType = Integer.class)
public class Age {
    private final Integer value;
 
    public Age(Integer value) {
        this.value = value;
    }
 
    public Integer getValue() {
        return value;
    }
}

そしてその基本型を格納するフィールドを作り、それを引数に取るコンストラクタを作り、それを返却するためのメソッド getValue を実装する。

これでよい。

しかし、これだけだと値を作るのが面倒になる。基本型ならリテラルがあるのに、こいつは毎度 new しないといけないので、生成用のショートカットメソッドを作っておく。

    public static Age of(Integer value) {
        return new Age(value);
    }

Entity への組み込み

特に何か特別なことをする必要はなく基本型の代わりにドメインクラスを使えばよい

DAO での利用

このようになるだろう。ドメインクラスを引数に取ればいいのである。

@ConfigAutowireable
@Dao
public interface CustomerDao{
    @Select
    public List<Customer> selectByAge(Age age);
}

そうすると、自動的に getValue で値を引き込んでくれるという仕組み。

使うときは先程のメソッドを使って

List<Customer> cList = this.customerDao.selectByAge(Age.of(10));

こんな感じ。

これでわかると思うが、String のパラメータが並んでいて順番を間違えるということがほぼ起きない。 型が厳密に規定されているので。

作例

PK をドメイン化する

ID に使う Pk クラスと言うドメインクラスを作ってみる。

Id という名前にすると Entity のアノテーションとかぶってしまって都合が悪い

@Domain(valueType = Long.class)
public class Pk {
    private final Long value;
 
    public Pk(Long value) {
        this.value = value;
    }
 
    public Long getValue() {
        return value;
    }
    public static Pk of(Long value) {
        return new Pk(value);
    }
}

Entity のフィールドの名前は結果とのマッピングに使われるので型の名前とは関係が無い。

Enum をドメイン化

Enum がドメイン化できると DB 値を定義するドキュメントとなるので非常に有用である。 Enum は直接的なインスタンス化ができないので、明示的にこれを使って生成しろとメソッドを明示している。

@Domain(valueType = Integer.class, factoryMethod = "of")
public enum Gender {
    MALE(1, "man"),
    FEMALE(2, "woman");
    private final Integer value;
    private final String name;
 
    private Gender(Integer value, String name) {
        this.value = value;
        this.name = name;
    }
 
    public static Gender of(Integer value) {
        for (Gender gender : Gender.values()) {
            if (gender.value.equals(value)) {
                return gender;
            }
        }
        throw new IllegalArgumentException(value.toString());
    }
 
    public Integer getValue() {
        return value;
    }
    public String getName() {
        return this.name;
    }
}

これも使うのは他の型と同様で今使っている基本型の代わりにこの Enum を使うだけである。 そうすることで、Entity にその所定の Enum が生成されてセットされる。こりゃ便利だわ。

java/spring/spring_boot/doma/domain_class.txt · 最終更新: 2018-12-04 00:33 by ore