19

バックグラウンド

DDD + TDD+etcのスタック全体を実際に理解するための単純なアプリケーションを作成しようとしています。私の目標は、実行時にDALリポジトリクラスを動的に注入することです。これにより、ドメインおよびアプリケーションサービスレイヤーをテスト可能に保つことができます。私は今のところこれを達成するために「貧乏人のDI」を使用することを計画しています...それで私はスタートアップの近くの単純なコンソールアプリケーションでこれを行うでしょう:

    //貧乏人のDI、実行時にDALリポジトリクラスを注入
    var productRepository = new SimpleOrder.Repository.ProductRespository();
    var customerRepository = new SimpleOrder.Repository.CustomerRepository();
    var orderRepository = new SimpleOrder.Repository.OrderRepository();

    //ApplicationServicesレイヤーのこのクラスへのコンストラクターインジェクション
    // SimpleOrder.ApplicationFacade
    OrderEntry oe = new OrderEntry(customerRepository、orderRepository、productRepository);

この依存性注入を実現するために、次の3つのリポジトリインターフェイスを作成しました。

--ICustomerRepository
--IOrderRepository
--IProductRespository

典型的な実装:

    名前空間SimpleOrder.Domain.Interfaces
    {{
        パブリックインターフェイスICustomerRepository
        {{
            Customer GetCustomerById(int customerId);
            void SaveCustomer(顧客顧客);
        }
    }

** SaveCustomerは、ドメインレイヤーで定義されたCustomerモデルクラスを参照していることに注意してください。これは他のリポジトリの典型です。

ただし、どのプロジェクト/レイヤーに実装する必要があるかわかりません。ソリューションには5つのプロジェクトがあります。

  1. SimpleOrder.ConsoleClient(プレゼンテーション) -ここからアプリケーションとしてドメインの特定の実装を注入したい

  2. SimpleOrder.ApplicationFacade(アプリケーションサービス) -ドメイン内の低レベルのメソッドを調整する、分厚い高レベルの粗粒度のメソッド

  3. SimpleOrder.Contracts- プレゼンテーションサービスとアプリケーションサービス間の通信に使用されるDTOクラス

  4. SimpleOrder.Domain(domain / bll) -ドメインモデルクラスCustomer、Order、OrderItem、Product

  5. SimpleOrder.Repository(dal) -リポジトリインターフェイスを実装します

私が見ている私の選択肢は次のとおりです。

オプション1: SimpleOrder.Contracts..でリポジトリインターフェースを定義します。

PRO:さまざまな懸念事項やレイヤー間で契約を共有するために作成したので、ここに所属する必要があると思います。たとえば、DTOはここで定義されます。

CON:ただし、各インターフェイスのメソッドシグネチャはドメインモデルクラスを参照します。
つまり、SimpleOrder.Domainへの参照を追加する必要がありますが、SimpleOrder.Contractsが別のプロジェクトで参照されている場合は、SimpleOrder.Domainを実行する必要があります。これは正しくないと思います。

オプション2:上記と同じシナリオですが、SimpleOrder.Contractsで各ドメインモデルクラスのインターフェイスも定義して、リポジトリインターフェイスと実際のモデルクラスの結合を解除できるようにします。

例:

    名前空間SimpleOrder.Domain.Interfaces
    {{
        パブリックインターフェイスICustomerRepository
        {{
            ICustomer ** GetCustomerById(int customerId);
            void SaveCustomer(ICustomer customer);
        }

        パブリックインターフェイスICustomer
        {{
            int CustomerId {get; セットする; }
            文字列名{取得; セットする; }
            System.Collections.Generic.List Orders {get; }
        }
    }

影響:各ドメインモデルクラスは、関連するインターフェイスを実装する必要があります。すなわち、

    パブリッククラスCustomer:SimpleOrder.Domain.Interfaces.ICustomer
    {{
        public Customer()
        {{
            _orders = new List();
        }

        public int CustomerId {get; セットする; }
        public string Name {get; セットする; }

        プライベートリスト_orders;
        パブリック仮想リスト注文{
            get {return _orders; }
        }
    }

PRO:オプション1の問題を修正します。

CON:これにより、プロジェクト内のファイルの数(および認識される複雑さ)が爆発的に増加します。これは、各ドメインクラスにインターフェイスが関連付けられているためです。

オプション3: SimpleOrder.Domainでリポジトリインターフェースを定義する

影響:実行時にSimpleOrder.ConsoleClientからアプリケーションサービスレイヤー(SimpleOrder.ApplicationFacadeプロジェクト)に具象リポジトリクラスを挿入するには、SimpleOder.ConsoleClientにもSimpleOrder.Domainへの参照が必要です。

PRO:これはオプション1も解決します

CON:プレゼンテーション層がドメイン層について多くを知ることができるようになったため、プレゼンテーション層からドメイン層を直接参照することを避けようとしていました。将来、コンソールアプリケーションをWPFまたはASP.NET MVCアプリに置き換えると、2番目以降のプレゼンテーション層の実装がアプリケーションサービス層ではなくモデルのメソッドを呼び出そうとするリスクがあります。(ただし、オプション4ではこれを考慮しています。)

オプション4:インターフェイスをSimpleOrder.Domainに配置し、SimpleOrder.ConsoleClientからSimpleOrder.Domainを参照します。

PRO:上記のすべての問題を修正します。

CON: SimpleOrder.ApplicationFacadeの高レベルの分厚いメソッドへのアクセスのみを提供する必要があるのに、プレゼンテーション層からドメイン層の低レベルのメソッドへのアクセスを直接提供するため、これは正しくありません。

質問 私はこれらのそれぞれを試しましたが、オプション4に落ち着きましたが、それは私の口に悪い味を残します。より良いオプションはありますか?私はここで正しい方向に進んでいますか?

4

2 に答える 2

16

私があなたの質問について理解していることから、私はオプション4が最良であることに同意します。リポジトリインターフェースは、すべてのドメインオブジェクトの隣のドメインレイヤーで宣言する必要があります。上記のインターフェースの実装は、インフラストラクチャレイヤー(ドメインレイヤーを世界に接続するレイヤー)の一部である必要があります。六角形のアーキテクチャを見て、この動機のいくつかを確認してください。

オプション4の欠点に対処するために、コンソールアプリを単なるプレゼンテーション層と見なすべきではありません。また、アプリケーションのホストやDI用語での構成ルートなど、他の責任もあります。アプリケーションサービスとのみ通信するコンソールアプリのプレゼンテーションコンポーネントが存在する可能性があります。ASP.NETWebAPIで実装されたオープンホストサービスの背後にアプリケーションサービスをカプセル化することもできます。その場合、プレゼンテーション層はこのサービスのみを参照し、基盤となるドメイン層から隠されます。

于 2012-12-12T18:45:07.273 に答える
0

私はeulerfxに同意します。私が追加する唯一のことは、従来のN層アーキテクチャでは、すべてをデータベースに依存させ、抽象化を使用してそれらの依存関係を解消するため、正しく感じられないことです。

オプション4で依存関係を整理する方法の例であるOnionArchitectureを確認する必要があります。個人的には、これが利用可能な最もスケーラブルなアーキテクチャモデルであると信じています。このアーキテクチャをDDDプラクティスと組み合わせると、最小限の労力で最大限の柔軟性を得ることができます。

ちなみに、私が見た多くの実装は、リポジトリとドメインサービスの契約を独自のプロジェクトに分割します。ただし、これは純粋に組織的な決定です。ドメインモデルプロジェクト内にそれらを含めることは完全に有効です。

于 2012-12-18T18:20:04.780 に答える