値オブジェクトとは
DDDにおける「値オブジェクト」は何かを計測したり、定量化したりして説明する際に使用するオブジェクトです。数字/文字列/日付をはじめ、姓/名/金額/色といった「ユビキタス言語」を表現するために活用します。例えば、電話番号を数値型(Int型)ではなくPhoneNumber型を作ることで、ドメインの業務をプログラムでわかりやすく示すことができます。
5章で紹介した「エンティティ」とは対照的に「一意に識別して変更を管理する必要がないモノ」を値オブジェクトとします。適切に設計していれば、値を想定外に書き換えられてしまうリスクが無いため安心して開発できます。そのため、使いやすくテストしやすいメリットがあります。保守性や可読性に優れているため、DDDでは積極的に使用することが推奨されています。
値オブジェクトの特徴(1)
IDDD本では値オブジェクトの特徴として、次の6つを必ず満たすべきと述べられています。
No | 値オブジェクトの特徴 | 説明 |
---|---|---|
1 | 計測/定量化/説明 | ドメイン内の何かを計測したり定量化したり説明したりする |
2 | 不変性 | 状態を不変に保つことができる |
3 | 概念的な統一体 | 関連する属性を不可欠な単位として組み合わせることで、概念的な統一体を形成する |
4 | 交換可能性 | 計測値や説明が変わったときには、全体を完全に置き換えられる |
5 | 等価性 | 値が等しいかどうかを、他と比較できる |
6 | 副作用のない振る舞い | 協力関係にあるその他の概念に「副作用のない振る舞い」を提供する |
DDD本における値オブジェクトの解説
値オブジェクトにはプログラムをシンプルにしてくれるメリットがありますが、本当に値オブジェクトでいいのかという判断に迷う局面がよくあります。IDDD本では、値オブジェクトを使用するかの判断基準として、エヴァンス氏の次の説明を引用しています。
あるモデル要素について、その属性しか関心の対象とならないのであれば、その要素を値オブジェクトとして分類すること。値オブジェクトに、自分が伝える属性の意味を表現させ、関係した機能を与えること。値オブジェクトを不変なものとして扱うこと。同一性を与えず、エンティティを維持するために必要となる複雑な設計を避けること。
このようにエヴァンス氏は「モデル自身の属性にしか関心がないか」を見極めることが重要な視点であると述べています。
なお、書籍『エンタープライズ アプリケーション アーキテクチャ』(PofEAA:2005年)で補足されている通り、Value Object(値オブジェクト)は特定のコミュニティではDTO(データトランスファーオブジェクト/レイヤ間の詰め替え用オブジェクト)の意味でも使われていました。過去の文献でValue Objectという用語が出てきた場合にはどちらの意味で使われているかに注意したほうがいいでしょう。
それでは、これらの特徴について順に紹介していきます。
(1)計測/定量化/説明
値オブジェクトはドメインの何かを計測、定量化、説明した結果となります。例えば年齢や名前の場合、以下の定量化/説明を行っています。
値オブジェクトの例 | 計測/定量化/説明する値 |
---|---|
年齢 | 何年生きてきたのかを計測し、定量化した値 |
名前 | 何と呼ばれているかを説明した値 |
値オブジェクトでは、それらが扱っている名前が「適切に値を計測/定量化/説明しているか」意識することが重要といえます。
(2)不変性
値オブジェクトはオブジェクトの生成時に値を設定することはできますが、その後、値を変更することはできません。従来のプログラムでは値の変更は当然だったと思いますが、DDDの値オブジェクトでは値が変更できない「不変性」を持っています。このことにより以下のメリットを受けることができます。
メリット | 説明 |
---|---|
シンプルで安全 | 利用者の想定外の更新操作が原因で、矛盾した状態に陥ることがない。そのため利用者がオブジェクトの内部状態を気にせずに安心して使える。 |
スレッドセーフ | マルチスレッドプログラミングにて、単一オブジェクトに対する複数スレッドにおける更新競合を制御する考慮が不要となる。 |
キャッシュ | 値が変化しないことが保障されているため、安心してオブジェクトをキャッシュできる。 |
プログラムの実装としては、コンストラクタでのみ値を設定できるようにして、オブジェクト外部から操作できるセッターは用意しません。
前章で紹介したエンティティは「状態が変化していくオブジェクト」でしたが、対照的に値オブジェクトは「不変なオブジェクト」といえるでしょう。