[DDD]ValueObject

  • 2018.06.10
  • DDD
[DDD]ValueObject

概要

ドメイン駆動設計のモデリングにおける要素の一つ、Value Object(値オブジェクト)の解説です。

DDD 関連記事リンク

◆ ValueObject(イマココ)
記事リンク: https://nrslib.com/valueobject/
◆ Entity
記事リンク: https://nrslib.com/entity/
◆ AggregateRoot
記事リンク: https://nrslib.com/aggregateroot/
◆ Repository
記事リンク: https://nrslib.com/repository/

解説

ValueObject は属性を表現します。

例えばユーザーを表現しようとしたときには以下の要素が属性にあたります。

  • 氏名
  • 電話番号
  • 誕生日

これらの情報をプログラムで表現するときの型を文字列日付型といった汎用的なものではなく、氏名型電話番号型などの特殊化された型で表現するのが ValueObject です。

何故、特殊化された型で表現するのでしょうか。

名前を持つユーザークラスを題材に考えてみます。


非常にシンプルで ValueObject の必要性がなさそうに思えるクラスですが、例えば
「ユーザー名が 3 文字以上である」
ということを強制する必要があった場合にはどのように実装することになるでしょうか。

概ね以下のようになると思います。


もちろん、このコードで目的は達成されているので問題はありません。

しかし、この「ユーザー名が 3 文字以上である」という情報は、果たして User クラスが持つべき情報でしょうか。

次に、今度はこの User クラスに電話番号を登録できるようにしてみます。


「電話番号の正規表現」でチェックしつつ設定できるようなメソッドを追加しました。

この「電話番号の正規表現」も、User クラスが持つべき情報でしょうか。
先ほどのユーザー名のときよりも際立って浮いているように思えます。

更に追加で企業情報のためのクラスを作り、User と同じように電話番号を登録できるようにしてみます。

「電話番号の正規表現」が User クラスと Company クラスの両方に記述されることになりました。

もちろんそれぞれのクラスを単体で見たときには、余り問題にはならないでしょう。
しかし、もし万が一電話番号の桁数が増えたり、ハイフンを含まないようになったときを考えると、その修正はどこまで広がることになるでしょうか。

試しに電話番号が携帯電話かどうかをチェックできるようにしてみます。


電話番号が携帯電話かどうかをチェックするための知識が複数個所に記述されてしまい、だいぶひどいことになるのがわかると思います。

こういった知識を本来あるべき場所に記述し、変更に強くするために ValueObject を利用します。

ユーザー名や電話番号を表現した ValueObject を利用した場合は以下のようになります。

ValueObject を使ったことによって、「ユーザー名が 3 文字以上である」という知識は UserName に移動し、「電話番号の正規表現」という知識は PhoneNumber に移動しました。

User クラスはこれらのクラスを受け取るようにしたことで、それが正しく設定されているかについて関与する必要がなくなっています。

もし、「電話番号の正規表現」を変更する場合も User や Company を変更する必要はなく、PhoneNumber クラスを変更するだけでよくなります。

まとめ

ValueObject の実装自体は非常に単純なものです。
愚直に実践するとクラスが多くなるという都合上、非常に敬遠されがちなものであります。

どのレベルから ValueObject にすべきかの方針は、その属性が知識を持つべきかどうかを判断基準にするのがよいかと思います。

DDDカテゴリの最新記事