シナリオ:
顧客が注文し、製品を受け取った後、注文プロセスに関するフィードバックを提供します。
次の集計ルートを想定します。
- お客様
- 注文
- フィードバック
ビジネスルールは次のとおりです。
- 顧客は自分の注文についてのみフィードバックを提供でき、他の人のフィードバックは提供できません。
顧客は、注文に対する支払いが済んでいる場合にのみフィードバックを提供できます。
class Feedback { public function __construct($feedbackId, Customer $customer, Order $order, $content) { if ($customer->customerId() != $order->customerId()) { // Error } if (!$order->isPaid()) { // Error } $this->feedbackId = $feedbackId; $this->customerId = $customerId; $this->orderId = $orderId; $this->content = $content; } }
ここで、企業が新しいルールを望んでいると想定します。
顧客
Supplier
は、注文の商品がまだ稼働している場合にのみフィードバックを提供できます。class Feedback { public function __construct($feedbackId, Customer $customer, Order $order, Supplier $supplier, $content) { if ($customer->customerId() != $order->customerId()) { // Error } if (!$order->isPaid()) { // Error } // NEW RULE HERE if (!$supplier->isOperating()) { // Error } $this->feedbackId = $feedbackId; $this->customerId = $customerId; $this->orderId = $orderId; $this->content = $content; } }
最初の2つのルールの実装をFeedback
集約自体の中に配置しました。特に、Feedback
集合体が他のすべての集合体をIDで参照しているので、これを行うのは快適
です。たとえば、Feedback
コンポーネントのプロパティは、他の集約の存在を知っていることを示している
ので、これらの集約の読み取り専用の状態も知っておくと安心です。
ただし、そのプロパティに基づいて、Feedback
アグリゲートはアグリゲートの存在を認識していないSupplier
ため、このアグリゲートの読み取り専用の状態を認識して
いる必要がありますか?
ルール3を実装する別のソリューションは、このロジックを適切なに移動することCommandHandler
です。しかし、これはドメインロジックを私のオニオンベースのアーキテクチャの「中心」から遠ざけているように感じます。
Supplier
アグリゲートの動作状態は、Order
リポジトリを介して照会されません。Supplier
およびOrder
2つの別個の集合体です。次に、DDD / CQRSメーリングリストで、集約ルートとリポジトリを他の集約ルートメソッド(コンストラクタを含む)に渡すことについて質問がありました。さまざまな意見がありましたが、グレッグヤングは、集約ルートをパラメーターとして渡すことは一般的であると述べましたが、別の人は、リポジトリーはドメインよりもインフラストラクチャーに密接に関連していると述べました。たとえば、リポジトリは「メモリコレクションで抽象化」され、ロジックがありません。
Customer
が自分の注文の1つにのみフィードバックを提供できるように($order->customerId() == $customer->customerId()
)、サプライヤーID($order->supplierId() == $supplier->supplierId()
)も比較する必要があります。最初のルールは、ユーザーが誤った値を入力するのを防ぎます。2番目のルールは、プログラマーが誤った値を指定しないようにします。それにもかかわらず、サプライヤが動作しているかどうかのチェックは、Feedback
エンティティまたはコマンドハンドラのいずれかで行う必要があります。質問はどこですか。