web-dev-qa-db-ja.com

DDD-継承とリポジトリの集計、この状況を正しく設計するにはどうすればよいですか?

私はレガシー倉庫システムに取り組んでいます。対応するProductを持つProductRepositoryの集約ルートが1つあります。

現在、私は次のことを言う新しい要件を持っています:

Some Products are Purchasable and need to keep track of the datetime they have become purchasable.

したがって、この要件を実装するために、「is-a」関係がわかるため、PurchasableProductを継承するProductという新しいクラスを作成し、この新しい属性を追加するというアプローチをとることにしました。

class PurchasableProduct(Product):
    def __init__(product_properties, purchasable_datetime):
        super().__init__(product_properties)
        self.purchasable_datetime = purchasable_datetime

今私を悩ませているのはリポジトリです。もちろん、ProductRepositoryは、Productsのインスタンスを返す必要があります(PurchasableProductsである場合でも)。ただし、これらのPurchasableProductsを取得して保存する方法が必要です。 PurchasableProductsRepositoryを追加することは解決策のようですが、ProductRepositoryPurchasableRepositoryの2つのレポジトリを作成できるので、PurchasableProductsのインスタンスを保存するために使用できます。

DDDパラダイムでは、集約ルートが別のルートの特殊化であるというこの状況を実装する最良の方法は何でしょうか?

あなたの直感は正しいです。ProductとPurchasableProductの両方をProductRepositoryから取得する必要があります。

これは問題ではありません。一方が他方から継承するため、PurchasableProductフィールドを追加してデータベースに追加のテーブルを追加し、Product selectステートメントに左結合してから、新しいProductをインスタンス化して入力する代わりにnullでない場合は、新しいPurchasableProductをインスタンス化します。それでも製品の配列/リストを返すことができます。たとえば、オーバーライドされたPurchase()メソッドを呼び出すと、PurchasableProductはその日付をチェックし、Productはチェックしません。

基本的に、クラスのサブタイピングは、Purchaseメソッドの条件ステートメントとProductの一部のnull許容フィールドを置き換えるだけです。そのすっきりしたコードですが、アプリケーションの全体的なフローを変更するべきではありません。

購入可能な製品のみを取得する必要がある場合は、GetProductsWhichArePurchasable()メソッドをリポジトリに追加して最適化できるようにすることができます。それでもProductsまたはPurchasableProductsのリストを返すかどうかは興味深いです。純粋主義者は製品にこだわると思いますが、とにかくあなたが最適化しているので......

2
Ewan

2つのリポジトリを持つことができるのは奇妙なことです

それに慣れる。

ユースケースを明示的に をモデル化することは、長い間優れたプラクティスと見なされてきました。アプリケーションの観点からは、集約ルートの特定のフレーバーへの参照を提供する役割を果たすリポジトリへの参照があります。

だからあなたは持っているかもしれません

interface Product {
    // ...
}

interface ProductRepository {
    Product get(Id id);
}

interface PurchasableProduct {
    // ...
}

interface PurchaseableProductRepository {
    PurchasableProduct get(Id id);
}

PurchaseableProductsRepositoryにワイヤリングされたPurchaseableProductsにアクセスする必要があるユースケース。

アプリケーションは、基礎となる実装が同じかどうかを知る必要はありません。

基礎となる実装は間違いなくトリッキーになる可能性があります。たとえば、その情報を知らないリポジトリを使用して製品が更新された場合に、購入可能な日付時刻を失いたくないとします。

私がそれを考えるようになった方法:集約の永続的な表現は、ドメインモデルの過去のバージョンから現在までのmessageです。 (および将来)。したがって、メッセージの互換性の基本原則が引き続き適用されます。必要なのは must-ignore and must-forward セマンティクスです。

つまり、ProductRepositoryを使用してPurchaseableProductを格納する場合、実装が何も知らないプロパティを上書きしないようにする必要があります。

5
VoiceOfUnreason