14

私はMVCアプリケーション用にいくつかのリポジトリを構築しており、リポジトリ間で責任を分担する正しい方法を考え出そうとしています。ほとんどの場合、これは明らかです。しかし、正しい答えが何であるかわからない特定のケースが1つあります。

このアプリケーションのユーザーは、従業員の複数のタイプの時間を追跡する必要があります。簡単にするために、2つだけを考えてみましょう。それらを「タイムカード」と「出席」と呼びます。これら2つの違いの正確な性質はそれほど重要ではありませんが、エンドユーザーはこれらを完全に別個のデータと見なしていることに注意してください。しかし、彼らがそれらを完全に別個のデータと見なす理由は、過去にそれらを一緒に見る機会が実際になかったからだと思います。どちらのタイプのレコードも、レコードの編集に関してほぼ完全に異なるビジネスルールを持っていますが、一般的に言えば、従業員が特定の時間にいた場所の両方のレコードでもあります。どちらのタイプの時間レコードにも、合計時間数など、多くの共通のプロパティがあります。と時間を収集した従業員。どちらのタイプにも、個々のタイプに完全に固有のいくつかのプロパティがあります。これらの「余分な」プロパティは、別のタイプのインスタンスに保持されています。したがって、一般的な構造は次のようになります。

class TimeRecord 
{ 
    Person Employee { get; set; }
    TimeSpan? Hours { get; set; }
}

class TimeCardData
{
     TimeRecord Record { get; set; }
     TProperty TimeCardProperty  { get; set; }
}

class AttendanceData
{
     TimeRecord Record { get; set; }
     TProperty AttendanceProperty  { get; set; }
}

したがって、問題は、ここで必要なリポジトリの数です。

1リポジトリ

リポジトリが1つしかない設計では、「タイムカード」、「出席」レコード、または両方のタイプを1つのリストに返すメソッドが公開されます。これはリポジトリのクライアントにとってはかなり便利ですが、私の考えでは、非常に太ったクラスになる危険性があります。「タイムカード」だけのリポジトリは、複雑なビジネスルールのせいで「出席」を処理しなくても、すでにシステム最大のリポジトリの1つになっていると思います。

2つのリポジトリ

別の設計には、「タイムカード」用の1つのリポジトリと、「出席」レコード用の別のリポジトリがあります。これには、たとえば「タイムカード」のビジネスルールがそれ自体で設定されているという利点があります。ただし、タイプに関係なく、すべての時間レコードのリストを取得する方法も必要です。この場合にどのリポジトリを使用するかは明確ではありません。両方?

3つのリポジトリ

「タイムカード」用の1つのリポジトリ、「出席」レコード用の別のリポジトリ、およびすべてのタイムレコードの読み取り専用リストを配信するための3番目のリポジトリを備えた設計も可能です。2リポジトリの設計と同様に、これには、たとえば「タイムカード」のビジネスルールがそれ自体で適切に配置されているという利点があります。結合されたリストをどこで入手できるかが明確になりました。しかし、2つの異なるリポジトリから同じレコードを取得できるのは少し奇妙だと思います。

ハイブリッド

ハイブリッドアプローチでは単一のリポジトリを使用しますが、ビジネスルールコード(レコードの選択を含む)を個別のタイプに移動します。この例では、単一の「タイムレコードリポジトリ」が「タイムカード」と「出席」時間のビジネスルール実装クラスのインスタンスを集約します。これが私が今好んでいるアプローチだと思います。

他の?

私が見逃したものはありますか?あるデザインを他のデザインよりも説得力のある議論はありますか?

4

1 に答える 1

18
  1. リポジトリは、少なくとも私の知る限りでは、ビジネス ルールの場所です。それらは、コレクションを模倣するための単なるファサードです。その下にあるのは、基本的に純粋なデータ アクセスです (それが仕事である場合は、リポジトリでも何も保持していない可能性があります)。そのため、「ビジネス ルール」の理由から、個別のリポジトリを考慮すべきではありません。

  2. ドメイン オブジェクトが本当に個別のオブジェクトである場合は、個別のリポジトリを用意する必要があります。リポジトリとは何かを思い出してください。それはファサードです。それはあなたのドメインへのコレクションを模倣します。リポジトリに関する非常に優れたブログ投稿については、こちらを参照してください: http://devlicio.us/blogs/casey/archive/2009/02/20/ddd-the-repository-pattern.aspx

リポジトリはファサードです。抽象化。

そうは言っても...私はあなたが別々のオブジェクトを持っているとは思わない。ここには、リポジトリとは関係なく、ドメインとドメインの設計に関係する問題がいくつかあります。2 種類の「タイムカード」は、実際には 2 つの異なるものですか、それとも同じものですか?

あなたは、「でも、2 つの異なるリポジトリから同じレコードを取得できるのは少し奇妙だと思います」と言います。

つまり、これらは実際には同じデータであり、異なる方法で表現されていることがわかります。そして、それを処理する方法があります。

これが実際に当てはまる場合、ここにあるのは共通の基本クラスのサブクラスです (たとえば、DB で非常に簡単にモデル化でき、NHibernate でエレガントに処理できるもの)。

私が取り組んでいるプロジェクトの例を紹介します。「ブロードキャスト」と呼ばれるものがあります。これは基本クラスです。概要。インスタンス化できません。このクラスには、DeviceBroadcast と FileBroadcast という 2 つの具体的な型があります。1 つはデバイス (DirectX キャプチャ カードなど) からオーディオ/ビデオをストリーミングし、もう 1 つはファイル ソース (.mp3 など) からオーディオ/ビデオをストリーミングします。

Broadcast オブジェクトを返すリポジトリが 1 つあります。FileBroadcast にキャストして FileBroadcast に関する特定の情報を操作するか、同じ理由で DeviceBroadcast にキャストできます (そのタイプの場合)。ブロードキャストを FileBroadcast と DeviceBroadcast の両方のタイプにすることはできません。どちらかでなければなりません。

データベースでは、一般的なブロードキャスト パラメータを Broadcast テーブルに格納し、次にファイル固有のプロパティを FileBroadcast テーブルに格納します。同じことが DeviceBroadcast テーブルにも当てはまります。分ける。ただし、リポジトリを介してクエリを実行すると、ブロードキャストが必要になります。これが私のルート集約オブジェクトであり、それが私のリポジトリです。

Broadcast 基本クラスには、両方のサブクラスが使用する共通のメソッドがあります (VLC プロセスを起動するための特定のコマンドライン引数を返す GetCommand() メソッドなど)。そのメソッドは抽象的であるため、サブクラスはそのメソッドをオーバーライドして実装する必要があります。このように、FileBroadcast 独自の「ビジネス ロジック」が FileBroadcast クラスに含まれています。DeviceBroadcast に固有の「ビジネス ロジック」は、DeviceBroadcast クラスに含まれています。両方に共通するロジックは、スーパークラスであるブロードキャストに含まれています。

ここでも同様の状況があるようです。そのため、私のデザインを共有しています。私はそれがあなたに役立つかもしれないと思います。

何よりも、ドメインとデータについて考えてください。別々のリポジトリを介して重複データを取得する場合は、ドメインの設計方法をさらに検討する必要があります。ユーザーにドメインの設計を指示させないでください。彼らは自分たちの観点からドメインを知っています。あなたがしなければならないことは、彼らが理解できる方法でデータを提示できることだけです。これは、悪い設計をしなければならないという意味ではありません。コードはドメインを使用する必要があるため、舞台裏で優れた設計を行うことができます。

于 2009-02-24T21:22:14.560 に答える