構成要素
以下「自分なりに」解釈したものを含みます。
- Entity: 何らかのIDによって識別されるオブジェクト。
- DB上で言えばPKを持つもの。
- Value Object: そのオブジェクト自体が持つ値によって識別されるオブジェクト。
- 共有される可能性があるため、不変でないといけない1。
- Service: 何も状態を持たないもの。
- 実装
- staticメソッドでも問題なさそう?
- Serviceのinterfaceと実装を分離するならstaticでなくなりますが、正直冗長な気もしますね。
- 実装
基本はこの3つ。
- Aggregates: 関連するオブジェクトの集まり。
- 不定数のリストとして表されることもあれば、車のタイヤのように決まった数のオブジェクトをまとめたものもあれば、複数バラバラのインスタンスの寄せ集めのこともある。
- 要はこれらを抽象化した概念と思われる。
- 逆に、Entityの特殊なパターンとも考えられそう。
- 基本的にはルートから操作しないといけない。
- 実装的には、メンバ変数をそのまま返すことは避ける。あるいは返すとしても、Collection.unmodifiableXXX()などを使って不変にするのが望ましい。
- Factory
- インスタンスやインスタンスの集約を生成するクラス。
- Builderパターンも含まれるため、statelessではない(よって他のものには当てはまらない)。
- コンストラクタで良い場合の基準が書かれているが、ここは難しいデスネ2。
- インスタンスやインスタンスの集約を生成するクラス。
- Repository
- DBアクセスを抽象化した「ようなもの」。「ようなもの」と書いているのは、単にSQLを隠蔽するとかというレベルじゃなくて、もっと抽象化されたものとして扱うから。
- Transactionはこの範囲外と書かれている。
ファクトリの使い分け
個人的にはこれがいいんじゃないかなぁというのを書いてみます。 フレームワークなどで対応している場合は除きます。
- Value Object: Factory Method
- 簡潔に書ける、immutable、Flyweightパターンが適用可能だから。
- Entity: Builder
- mutableなことが多いため。
- Repository: Factory Method
- コンストラクタでもいいですが、テストのことを考えると、インタフェースを作っておいたほうが楽そう。
- Service: コンストラクタ
- staticメソッドで書けるケースも多そうですが、慣習として避けたほうがいいかも。
- Repositoryを内部で持つなら取り替えられる方がいいかなと。。。これは組んでみないとなんとも。