DDDの値オブジェクト

あるモデルの要素において,その属性のみに関心を払う必要があれなそれは値オブジェクトとして表現する.

値オブジェクトは不変なものとして扱いエンティティの設計で考えたような一意な識別子による同一性などは考える必要がない.

値の特徴

インスタンスを値オブジェクトとして表現するかエンティティとして表現するかの判断はその概念が以下の特性を持っているかによって考える.

  • そのドメイン内の何かを計測したり定量化したり説明したりする
  • 状態を不変に保つことができる
  • 関連する属性を不可欠な単位として組み合わせることで概念的な統一体を形成する
  • 計測値や説明が変わった時には全体を完全に置き換える
  • 値が等しいかどうかを他と比較できる
  • 協力関係にあるその他の概念に副作用のない振る舞いを提供する

計測・定量化・説明

値オブジェクトで表現されるものはドメイン内のモノではなく,概念でありドメイン内のモノを計測したり定量化したり説明したりする.

不変

値オブジェクトは一度作ると変更できない.インスタンス生成時にはコンストラクタですべてのパラメータを渡して値の状態を組み立てる.例えばオブジェクトの状態を変更できるメソッドをセッターやイニシャライザだけにしておいてそれらを全てprivateスコープにしておく.

概念的な統一体

値オブジェクトはその各要素だけでは意味をなさず,概念的な統一体が意味を成す.

交換可能性

モデル内のエンティティが不変な値を参照として保持している場合において,その値がが示す現在の状態が変化した場合は値全体を新しいもので置き換えて,正しい状態を反映させる.

FullName name = new FullName("Vaughn", "Vernon");
// ... 色々なことがあって状態が変わる
name = new FullName("Vaughn", "L", "Vernon");

値の等価性

2つのオブジェクトの等価性を判断する場合はオブジェクトの型が等しく全ての属性の値が等しいことを確認する.

副作用のない振る舞い

不変な値オブジェクトのメソッドは全て副作用のない関数でなくてはならない.(副作用があるとメソッドによって自身の状態が変わるので不変性を保てない)

コマンドクエリ分離原則では副作用のない関数をクエリと呼ぶ.例えば以下のようにオブジェクトに対して何らかの問いかけをおこない答えを得るような関数.

FullName name = new FullName("Vaughn", "Vernon");
// ...some codes
name = name.withMiddleInitial("L");

関数の実装は適当だがこんな感じ.

public FullName withMiddleInitial(String aMiddleNameOnInitial) {
// some assertion
  String middle = aMiddleNameOnInitial.trim;
  return new FullName(
this.firstName(),
middle.substring(0, 1).toUpperCase(),
this.lastName()
);
}

この関数では自身の属性,状態は変更せず新しいインスタンスを返す.

Show your support

Clapping shows how much you appreciated hida’s story.