Entity

Entityとは

Entityは、業務から見つけた概念をコードで表すための、ドメインモデルの構成要素です。その概念を、名前や状態ではなく同一性によって区別する必要があるとき、Entityとして表します。

Entityを使うと、情報が変わっても以前から続くものとして扱い、反対に、情報が同じでも別のものとして区別できます。

Entityの同一性

例えば、人には名前、住所、年齢などの属性があります。引っ越して住所が変わったり、誕生日を迎えて年齢が変わったりしても、別の人になるわけではありません。

システムでは、会員IDなどの識別子を使って一人ひとりを区別します。属性が変わっても会員IDが同じであれば、同じ人の情報が変更されたものとして扱います。このように、属性が変わっても「その人であること」が変わらない性質を同一性と呼びます。

Entityの特徴

状態が変わる
名前や状態などの属性を変更しても、別のEntityにはなりません。
属性が同じでも区別する
同じ商品を同じ数量で注文した二件の注文でも、注文IDが異なれば別の注文です。
同一性を持つ
どのEntityであるかを識別子で区別し、識別子が同じなら属性が変わっても同じEntityとして扱います。

具体例で整理する

前のページでは、参加者募集のドメインモデルとして「募集」「参加申込み」「申込期限」などを見つけました。ここでは「募集」を例にします。

募集の開催場所が渋谷から新宿へ変更されたとします。開催場所が変わっても、募集IDはrecruitment-1のままなので、変更前と同じ募集だと判断できます。

変更前

募集ID:recruitment-1

開催場所:渋谷

変更後

募集ID:recruitment-1

開催場所:新宿

「募集」は、開催場所などの属性が変わっても、募集IDによって変更前と同じ募集として区別できるため、Entityとして表します。

コードで表す

募集をEntityとして表すと、例えば次のようになります。

TypeScript

// 「募集」を表すEntity
class RecruitmentEntity {
  constructor(
    // 募集の同一性を表す識別子
    readonly id: string,

    // 変更されることがある募集の属性
    private title: string,
    private location: string,
  ) {}

  // 開催場所を変更する
  changeLocation(newLocation: string) {
    this.location = newLocation
  }

  // 同一性はIDで比較する
  isSameAs(other: RecruitmentEntity) {
    return this.id === other.id
  }
}

RecruitmentEntityは、開催場所を変更できる一方で、IDは変更できません。二つの募集が同じかどうかは、タイトルや開催場所ではなくIDで判断します。

フットサルNOWでの配置例

src/features/futsal/
└── domain/                      ← ドメインモデルを置くディレクトリ
    ├── recruitment/
    │   └── RecruitmentEntity.ts ← Aggregate Root(Entity)
    └── ...                      ← ほかのドメインモデル

※ これはフットサルNOWでの配置例です。DDDが特定のディレクトリ構成を定めているわけではありません。

※ このガイドラインでは、ファイル名やクラス名だけで役割を見分けやすくするため、DDD上の役割を名前に付けています。