前回のふりかえり
- 第6章(集約)の主旨
- ライフサイクルの長いオブジェクトの整合性を保つことが、ドメインオブジェクトを扱うことの課題になってくる。
- そのような課題に立ち向かうために
集約
・ファクトリ
・リポジトリ
といった要素を使う。
- そのような課題に立ち向かうために
- 集約は関連するオブジェクトの集まりで、データ変更の単位になるもの。
- 境界・ルートエンティティといった要素を持つ
- 同一性やオブジェクトの参照を集約内で管理することで、同一性・整合性を保ちやすくする。
- ライフサイクルの長いオブジェクトの整合性を保つことが、ドメインオブジェクトを扱うことの課題になってくる。
第6章
ファクトリ(FACTORIES)
- オブジェクトの中には組み立てが複雑なものもある(自動車とか)
- 複雑な操作をオブジェクトにやらせると、オブジェクト本来の責務がわかりづらくなる。
→ ファクトリの出番
- ファクトリ:他のオブジェクトの生成を責務とするもの
優れたファクトリの条件
- 一貫した状態のオブジェクトだけを作る
- エンティティ: 不変状態を満たす。集約全体を生成する
- 値オブジェクト: 正しい状態に初期化されている
- 要求される型に応じて抽象化する
- 結合度を下げるため?(よくわかっていない)
ファクトリを作る場所について
一般的に...
- ファクトリ生成の目的
- 詳細を隠したいと思うものを構築するため
- 配置する場所
- 制御を行わせたい場所
上記を踏まえると、ファクトリメソッドは下記の場所に生成するのがよい
1. 集約のルートエンティティ
ファクトリで生成されたオブジェクトは、ルートエンティティに参照を保持される
2. 他のオブジェクトの生成に密接に関わるオブジェクト
オブジェクト生成はするが、そのクラスは生成物を所有しない
3. 独立したファクトリ
- ファクトリを所属させるのは、生成物にたいして自然で密接に関係するオブジェクトにするべき
- そのようなオブジェクト(場所)が無い場合は、独立したファクトリオブジェクト(or サービス)を作る
- ただし、アクセスは集約の内部に制限する
※ だが、対象が単純であればコンストラクタで事足りることもある
構造が単純なオブジェクトにまでファクトリを使うと、逆にオブジェクトが不明瞭になる
ファクトリの種類
- エンティティファクトリ
- 有効な集約を受け取るだけの、本質的な属性だけを受け取る
- エンティティの同一性を担保するための識別子について
- 識別子がユーザ指定のものなら、その値はファクトリの引数で渡す
- プログラムが識別子を用意するなら、それはファクトリで制御する
- 値オブジェクトファクトリ
- 生成物を完全に記述する(生成後に値が変わることはないようにする)
- 再構成のためのファクトリ
- データベースの値からオブジェクトを再構築するためのファクトリ
- 再構成のためのエンティティファクトリでは、IDは既に割り当てられたものを使う
- 値オブジェクトファクトリでも不変条件を制御するが、違反した時の処理は柔軟性が必要。(生成時の様に処理を中止するのが適切でない場合もある)
- データベースの値からオブジェクトを再構築するためのファクトリ
※ データベースを元に作ったオブジェクトは厳密には「生成物」ではない。ライフサイクル中期のオブジェクト
思ったこと・気になったこと
- オブジェクトの組み立て操作をクライアントに任せると、ドメイン層の知識がクライアントに流出するというのはよくわかった。ただ、ファクトリの具体的な姿がよくわかっていないせいかちょっとしっくりきていない。
- ファクトリメソッドを作っても、引数が複数になるとクライアント側にもある程度組み立て作業(引数で渡すオブジェクトを用意する処理)は残ってしまうのではという疑問を抱いたけど...そもそもそのような事態になるのがおかしい?