3

バックグラウンド

Udi Dahan は、データ アクセスに使用する便利なパターンとしてフェッチ戦略を提案しています。同意します。

概念は、役割を明確にすることです。たとえば、集約ルート - 顧客があります。アプリケーションのいくつかの部分に顧客が必要です。選択する顧客のリスト、顧客の詳細のビュー、および顧客を非アクティブ化するボタンが必要です。

Udi は、これらの役割ごとにインターフェイスを提案するようです。そのため、購入した最新の 10 個の製品を含むICustomerInList非常に基本的な詳細と、顧客を非アクティブ化する方法があります。各インターフェイスは、それぞれの状況でジョブを完了するのに十分な数の Customer Aggregate Root を公開します。My Customer Aggregate Root は、これらすべてのインターフェースを実装しています。ICustomerDetailIDeactivateCustomer

ここで、これらのロールごとにフェッチ戦略を実装したいと考えています。各戦略は、必要な情報のみを公開するインターフェースの背後にあるため、集計ルートに異なる量のデータをロードできます。

この部分を実装する一般的な方法は、Service Locator または他のスタイルの依存性注入を要求することです。このコードは、たとえば、必要なインターフェイスをICustomerInList取得し、それをロードするためのフェッチ戦略を見つけます ( IStrategyForFetching<ICustomerInList>)。この戦略は、ICustomerInList インターフェイスに必要な情報を含む Customer のみをロードすることを認識しているクラスによって実装されます。

ここまでは順調ですね。

質問

Service Locator またはIStrategyForFetching<ICustomerInList>. 私が目にするすべての例は、既知の ID で 1 つのオブジェクトのみを選択しています。このケースは簡単です。呼び出し元のコードはこの ID を渡し、特定のインターフェイスを取得します。

検索したい場合は?それとも、顧客リストの 2 ページ目が必要ですか? ここで、Fetching Strategy が必要とするより多くの用語を渡したいと思います。

可能な解決策

私が見たいくつかの例では、述語 (特定の集約ルートが結果セットの一部である必要がある場合に true または false を返す式) を使用しています。これは条件には問題なく機能しますが、最初の n 人の顧客だけを取得する場合はどうでしょうか? または、検索結果の 2 ページ目を取得しますか? または、結果はどのようにソートされますか?

私の最初の反応は、汎用パラメーターを myIStrategyForFetching<ICustomerInList>に追加し始めることIStrategyForFetching<TAggregateRoot, TStrategyForSelecting, TStrategyForOrdering>です。これはすぐに複雑で見苦しくなります。リポジトリが異なると、さらに複雑になります。特定の選択方法を使用する場合にのみデータを提供するリポジトリもあれば、特定のタイプの順序付けのみを提供するリポジトリもあります。特定の方法でソートされた集約ルートのみを返す特殊なリポジトリとともに、ソート機能を使用できる一般的なリポジトリを柔軟に実装したいと考えています。

最初に使用したのと同じパターンを適用する必要があるように思えます - How do I make roles explicit? ペイロード Y (検索/順序付けパラメーター) を使用して X (集約ルート) を取得するための戦略を実装する必要がありますか?

編集 (2012-03-05)

毎回集約ルートを返さない場合でも、これはすべて有効です。各インターフェイスが異なる DTO によって実装されている場合でも、IStrategyForFetching を使用できます。これが、このパターンが強力である理由です。何を取得し、何を返すかを集約ルートにマップする必要はまったくありません。

使ってしまいましたIStrategyForFetching<TEntity, TSpecification>。TEntity は私が取得したいものであり、TSpecification は取得したい方法です。

4

2 に答える 2

3

CQRSに出くわしたことがありますか?Udiはその大きな支持者であり、その目的はこの正確な問題を解決することです。

最も基本的な形式の概念は、ドメインモデルをクエリから分離することです。つまり、ドメインモデルは、コマンドを実行したり、トランザクションをコミットしたりする場合にのみ機能します。画面に情報を表示するために、アグリゲートとエンティティからのデータを使用しません。代わりに、各画面に必要な正確なデータを提供するメソッドを含む個別のデータアクセスサービス(またはそれらの束)を作成します。これらのメソッドは、条件オブジェクトをパラメーターとして受け入れることができるため、必要な基準で検索を実行します。

これがどのように機能するかの簡単なシーケンス:

  • 画面には、先週注文した顧客のリストが表示されます。
  • UIは、基準として日付を渡すCustomerQueryServiceを呼び出します。
  • CustomerQueryServiceは、各顧客の集計IDを含め、この画面に必要なフィールドのみを返すクエリを実行します。
  • ユーザーはリストから顧客を選択し、「重要な顧客にする」アクション/コマンドの実行を選択します。
  • UIは、顧客のIDを含むMakeImportantCommandをコマンドサービス(またはDDD用語ではアプリケーションサービス)に送信します。
  • コマンドサービスは、コマンドで渡されたIDを使用してリポジトリからCustomerアグリゲートをフェッチし、必要なメソッドを呼び出してデータベースを更新します。

CQRSアーキテクチャを使用してアプリを構築すると、パフォーマンスとスケーラビリティに関する多くの可能性が開かれます。ビューごとに非正規化されたテーブル、結果整合性、およびイベントソーシングを含む個別のクエリデータベースを作成することで、この簡単な例をさらに進めることができます。CQRSに関するビデオ/例/ブログがたくさんあり、本当に興味があると思います。

あなたの質問が「フェッチ戦略」に関するものだったことは知っていますが、彼が2007年にこの記事を書いたことに気づきました。彼は、CQRSを後継者と見なしている可能性があります。

私の答えを要約すると:

  1. ドメインアグリゲートからDTOを削減しようとしないでください。代わりに、ニーズに合わせたクエリを提供する個別のクエリサービスを作成するだけです。
  2. CQRSを読んでください(まだ読んでいない場合)。
于 2012-03-02T14:02:08.417 に答える
1

デビッド・マスターズによる応答に追加するには、すべてのフェッチ戦略インターフェイスが不必要に複雑になっていると思います。カスタマー AR に、UI をモデルにしたさまざまなインターフェイスを実装させることは、AR クラスに対する不必要な制約であり、それを強制しようとすると多大な労力を費やすことになります。さらに、それは脆弱なソリューションです。Customer に関連しているが、customer クラスに属さないデータがビューに必要な場合はどうすればよいでしょうか? 次に、顧客クラスと対応する ORM マッピングにそのデータを含めるよう強制しますか? クエリ用に別のクラスのセットを用意して、それで完了しないのはなぜですか? これにより、戦略が属する場所 (リポジトリ内) でフェッチ戦略を処理できます。さらに、フェッチ戦略インターフェースの抽象化は実際にどのような価値を追加しますか? アプリケーションで何が起こっているかの適切なモデルかもしれませんが、そうではありません。

于 2012-03-03T02:13:39.423 に答える