Entity(エンティティ)
データベースのデータに対するビジネスロジックの置き場所として使うカスタムクラスです。
Entityの特徴
一意性のあるデータの一塊り
あるインスタンスは他のインスタンスと重複しない。ユニーク。
SQLなどで取得するデータの1行分
DBの型をプログラミング言語の型に置き換えたもの
varchar→string、real→float
ロジックのある項目はValueObjectにする。
なお、コンストラクタ内でValueObjectをnewする。画面ロジック側ではnewしないこと。
Entityなどの複数項目を使ったロジックを記述する。
Entity内の単一項目だけでなく複数項目を作ったロジックを記述するクラスになります。
基本的に継承はさせない。
継承させてもソースを読むのがややこしくなるため。
基本的には可変にする。
バリューオブジェクトは不変でしたが、エンティティは基本的に可変にします。なぜなら、値と違ってDBの値などは変更されて当たり前だからです。ただ、全く変更がないと想定される属性に関しては不変にした方が良いです。(バグ混入を防ぐため)
同じ属性であっても区別する。
例えば、ユーザーというエンティティは名前が変わったとしても、同一であると判断します。現実世界に置き換えてみればわかりますが、同姓同名の人がいたとしても別人として区別されます。
であれば、エンティティは何で同一性を判断するのかといえば、主キー(id)になります。
なぜEntityを使った方が良いか?
文字列でアクセスするとスペルミスをする可能性がある。
コンパイルエラーではなく、実行時エラーになってしまいバグに気づきにくい。
テストコードが書きやすくなる。
記述がしやすくなる。
ValueObjectが運べる
配置場所
Domainの中にEntitiesというフォルダを作って入れる。
結合エンティティについて
基本的には1テーブル、1エンティティという形でクラスを作ると良いです。
ただ、SQLのSELECT文で結合が発生する場合はどうでしょうか。
結論
基本的には、結合された結果のエンティティを作るのが良いです。(場合によっては1テーブルずつ処理した方が良い場合もありますので絶対ではないです。)
ただ、この考え方が絶対ではないので大事なのは開発者皆が同じ思想で作っていくことができる状況が一番大事だと思います。
なぜか?
データベースは正規化されており、結合というのは非正規系にするということでデータベース処理においてごく自然な行為になります。SQLの旨みを捨てる行為になってしまうので結合前提でクラスを作るのが良いわけです。
方法論の例
結合の発生するselect文はデータベースのビューにしてしまってそれに対してエンティティを作るというのが一番実体にあっているような気がします。
エンティティを作成する判断基準
「ライフサイクルがあり連続性があるかどうか」が大きなポイントです。
例
「ユーザー」は作成、変更、削除などのライフサイクルがあるオブジェクトになります。逆に、「姓名」のように最初に生成されてその後特に何も変化がないようなオブジェクトの場合はバリューオブジェクトとして生成すると良いでしょう。
判断は単純ではない
あるシステムではバリューオブジェクトになりうるオブジェクトでも、別システムではエンティティとして作成した方が良いケースだって存在します。
例えば、「部屋」という存在があったとしてある住所管理システムでは部屋は単なる情報でありバリューオブジェクトで良いでしょう。
ただ、ホテルのシステムとかであれば、「部屋」は空き状況が常に変化するエンティティオブジェクトとして生成することが望ましいでしょう。
仕様オブジェクトとして切り出すかの判断
例えば、ユーザーオブジェクトがあったときに、ユーザーが「扶養家族が5人以上の場合は減税あり、それ以外はなし」みたいなケースがあるとします。
その場合、こうした情報はドメインのルールになるので、エンティティオブジェクトでisTaxReducationというメソッドを作ったとしたら扶養家族の人数をデータベースに問い合わせないといけないです。ただ、エンティティの中で低レベルのレポジトリの操作は避けなければなりません。
対策
こうした場合に使えるのが、「仕様オブジェクト」としてエンティティから切り離すことです。こうすることでエンティティなどのドメインオブジェクトの肥大化を防ぎ可読性の高いドメインオブジェクトを保つことが可能です。
実装
以下のクラス、メソッドを作りレポジトリにアクセスして判定処理を記述します。
クラス名
「UserTaxReducationSpecification」みたいなクラスを作ります。
メソッド名
「isSatisfiedBy」というメソッドを作ります。
この記事へのコメントはありません。