エンティティとは
値オブジェクトと同じく、ざっくり言うと現実世界の物をクラスで表したもの。
他の用語であるエンティティ
データベースやJavaでもこの単語を利用するが、DDDにおいては意味合いが異なる。
上記ではデータベースの値をマッピングするクラスで用いられることが多いが、
DDDにおいてはそうではない。
値オブジェクトとの違い
値オブジェクトとの違いは、その性質にある。
値オブジェクトの性質(復習)
- 不変であること
- 交換可能であること
- 等価比較可能であること
エンティティの性質
- 可変であること
- 同じ属性をもっていても区別されること
- 同一性を持つこと
例:ユーザー
ユーザーは一般的にはエンティティである。
例えばユーザーが次の情報を持つとして、エンティティの性質について考えてみる。
- 氏名
- 年齢
イメージするのは次のようなクラスだ。
class User {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
性質①:可変であること
値オブジェクトは不変な性質を持つのに対して、エンティティは可変である性質を持つ。
例えばユーザーの年齢は誕生日が来たら変化する属性である。
年齢が20歳→21歳になったところで
別のユーザーになるわけではなく、同じユーザーの年齢という属性が変化する。
これは言い換えると、
年齢が上がった時に別のユーザーオブジェクトが新たに作られるのではなく、
さっきまで存在したユーザーオブジェクトの中にあるageの値が書き変わると言える。
性質②:同じ属性を持っていても区別されること
値オブジェクトは同じ属性を持っていた場合同一とみなされるが、
エンティティはそれだけでは同一とはみなされない。
例えば同姓同名の「山田太郎さん(20歳)」が2人いた場合、
それは「同一人物か?」と聞かれたら答えはNOである。
値オブジェクト | 属性(氏名と年齢)が一致しているため、同じと考える |
エンティティ | 属性(氏名と年齢)が一致しているものの、同姓同名の別の人物として区別する |
性質③:同一性を持つこと
性質②の説明で気づいたと思うが、ユーザーエンティティには同一人物を識別するためのIDが必要である。
このIDによって年齢が変わっても、改名したとしても同一人物であるということを区別できる。
つまり、上で説明したUserクラスだが、本来は以下のようにid
フィールドを追加した方が良い。
class User {
id: string;
name: string;
age: number;
constructor(id: string, name: string, age: number) {
this.id = id;
this.name = name;
this.age = age;
}
}
値オブジェクトとエンティティの違いは何か
値オブジェクトとエンティティはどちらもドメインオブジェクトであり、
その性質によって呼び方が変えられているだけである。
もちろん違いを理解していた方が良いが、
値オブジェクトもエンティティもやりたいことはほぼ一緒なのでそこまで難しく考えることはない。
この両者のドメインオブジェクトを活用することで
コードのドキュメント性が高まり、改修に強いシステムになるという目的が達成できれば良い。
何が良いのか?
エンティティのメリットは、値オブジェクトのメリットとほぼ同じであるが
追加で次のようなメリットも存在する。
メリット:値の変更に対してルールを設けることができる
例えばユーザー名を変更する機能がある場合、
エンティティにchangName
()メソッドを配置することで
ユーザーにはどんなふるまいがあるか分かり、異常値を排除することができる。
class User {
id: string;
name: string;
age: number;
// コンストラクタは省略
// 「ユーザークラスは名前を変更することができ、その場合3文字以上でなければならない」と分かる
changeName(name: string) {
if (name.length < 3) {
throw new Error("3文字未満のユーザー名に変更しようとしているためエラー");
}
this.name = name;
}
}
まとめ
- エンティティとはざっくり言うと「現実世界の物をクラスで表現したもの」
- 値オブジェクトもエンティティも性質が違うから呼び方が違うだけで、どちらもドメインオブジェクト
- 性質
- 可変であること
- 同じ属性をもっていても区別されること
- 同一性を持つこと
- メリット
- エンティティ内の値変更についてメソッド名でふるまいが分かる
- エンティティ内の値変更について異常値が入り込むことを防ぐ