この記事の目的
ドメイン駆動設計における値オブジェクトの実装例を紹介します。
「値オブジェクト」とは、値をオブジェクトとして扱うためにクラスにまとめたものです。
値をintやStringなどを使って表現したときと比較して下記の利点があります。
- 「値が守るべきルール」を1か所で実装すれば済む
- 値が守るべきルールとは、1文字以上でなければならないといったもの
- 「値を使った処理」をメソッドとして定義できる
- 値を使った処理とは、他の値と数を足し合わせるといったもの
実装例
1文字目を大文字、2文字目以降を小文字にした名前を表すCapitalizedNameクラスの実装例です。
ポイント
メンバ変数にはfinalを付与
メンバ変数とはクラスが保持する値のことです。実装例ではnameがメンバ変数にあたります。
コンストラクタで設定した値から変更できないようにして、分かりやすいプログラムにする目的があります。
@AllArgsConstructor(access = AccessLevel.PACKAGE)
メンバ変数を全て初期化するコンストラクタを生成するために付与します。
下記の理由で可視性はパッケージprivateにします。
- 他クラスでのインスタンス生成は後述のファクトリメソッドを使って行う
- 自動テストからは直接コンストラクタを呼び出したい
ファクトリメソッドで値が守るべきルールを実装
ファクトリメソッドとは、インスタンス生成のためのメソッドです。実装例では、valueOfメソッドがファクトリメソッドにあたります。
このメソッドに「値が守るべきルール」を含めて不適切なインスタンスの生成を防ぎます。実装例には下記2つのルールを含めています。
- nullや空文字はエラーにする
- 1文字目を大文字、2文字目以降を小文字に変換してからメンバ変数nameに保持
ファクトリメソッドにルールを集めておかないと、インスタンス生成を行うクラス側でルールを実装しなければなりません。同じルールの実装が複数のクラスに散らばる原因になります。
値を使った処理
実装例では@Getterによって生成されるnameの取得があたります。
ファクトリメソッド内で変換済であるため、「1文字目を大文字、2文字目以降を小文字に変換した値」を取得することができます。
@EqualsAndHashCode
値オブジェクトは別インスタンスであっても、メンバ変数が等しいとき(つまり値が等しいとき)はequalsメソッドの結果をtrueにしたいので付与します。
assertEqualsメソッドを使って自動テストを簡潔に書くことができる効果もあります。
@ToString
必須ではありませんが、自動テスト失敗時のログを分かりやすくするために付与します。
コメント