web-dev-qa-db-ja.com

ドメイン駆動設計:ドメインサービス、アプリケーションサービス

誰かがいくつかの例を提供することで、ドメインとアプリケーションサービスの違いを説明できますか?また、サービスがドメインサービスである場合、このサービスの実際の実装をドメインアセンブリ内に配置しますか?その場合、リポジトリをそのドメインサービスに挿入しますか?いくつかの情報は本当に役立ちます。

236
Chris

サービスには、3つのフレーバーがあります:ドメインサービスアプリケーションサービス、およびインフラストラクチャサービス

  • ドメインサービス:カプセル化ビジネスロジックドメインオブジェクトに自然に適合せず、NOT典型的なCRUD操作–これらは属するリポジトリに。
  • アプリケーションサービス:システムと通信するために外部の消費者が使用します(Webサービスと考えてください)。消費者がCRUD操作にアクセスする必要がある場合、ここで公開されます。
  • Infrastructure Services:技術的な問題を抽象化するために使用されます(MSMQ、電子メールプロバイダーなど)。

ドメインオブジェクトと共にドメインサービスを維持することは賢明です。それらはすべてドメインロジックに焦点を当てています。はい、リポジトリをサービスに挿入できます。

通常、アプリケーションサービスは両方のドメインサービスを使用しますandリポジトリは外部リクエストを処理します。

お役に立てば幸いです!

314
Vijay Patel

(読みたくない場合は、下部に要約があります:-)

私も、アプリケーションサービスの正確な定義に苦労しています。 Vijayの答えは1か月前の私の思考プロセスに非常に役立ちましたが、その一部に反対するようになりました。

その他の資料

アプリケーションサービスに関する情報はほとんどありません。集約ルート、リポジトリ、ドメインサービスなどのテーマについては広範囲に説明しますが、アプリケーションサービスについては簡単に説明するか、完全に省略します。

MSDN Magazineの記事 ドメイン駆動設計入門 は、ドメインモデルを変換および/または外部クライアントに公開する方法としてのアプリケーションサービスについて説明しています。 WCFサービスとして。これが、Vijayがアプリケーションサービスについて説明する方法です。この観点から、アプリケーションサービスはドメインへのインターフェースです

オニオンアーキテクチャに関するジェフリーパレルモの記事(パート onetwo 、および three )を読んでください。彼は、ユーザーのセッションなど、アプリケーションサービスをアプリケーションレベルの概念として扱います。これはアプリケーションサービスに対する私の理解に近いものですが、このテーマに関する私の考えとはまだ一致していません。

私の考え

私はアプリケーションサービスをアプリケーションによって提供される依存関係と考えるようになりました。この場合、アプリケーションはデスクトップアプリケーションまたはWCFサービスである可能性があります。

ドメイン

例の時間。ドメインから始めます。ここには、外部リソースに依存しないすべてのエンティティとドメインサービスが実装されています。外部リソースに依存するドメインの概念は、インターフェースによって定義されます。可能なソリューションレイアウトは次のとおりです(プロジェクト名は太字):

私のソリューション
- My.Product.Core (My.Product.dll)
-DomainServices 
 IExchangeRateService 
 Product 
 ProductFactory 
 IProductRepository 

ProductおよびProductFactoryクラスは、コアアセンブリに実装されています。 IProductRepositoryは、おそらくデータベースによってサポートされているものです。これの実装はドメインの関心事ではないため、インターフェイスによって定義されます。

ここでは、IExchangeRateServiceに焦点を当てます。このサービスのビジネスロジックは、外部Webサービスによって実装されます。ただし、その概念は依然としてドメインの一部であり、このインターフェイスで表されます。

インフラ

外部依存関係の実装は、アプリケーションのインフラストラクチャの一部です。

マイソリューション
 + My.Product.Core (My.Product.dll)
- My.Product.Infrastructure (My.Product.Infrastructure.dll)
-DomainServices 
 XEExchangeRateService 
 SqlServerProductRepository 

XEExchangeRateServiceは、 xe.com と通信することにより、IExchangeRateServiceドメインサービスを実装します。この実装は、インフラストラクチャアセンブリを含めることにより、ドメインモデルを利用するアプリケーションで使用できます。

応用

アプリケーションサービスについてはまだ言及していないことに注意してください。それらを今から見ていきましょう。迅速な検索にキャッシュを使用するIExchangeRateService実装を提供したいとしましょう。このデコレータクラスの概要は次のようになります。

public class CachingExchangeRateService : IExchangeRateService
{
    private IExchangeRateService service;
    private ICache cache;

    public CachingExchangeRateService(IExchangeRateService service, ICache cache)
    {
        this.service = service;
        this.cache = cache;
    }

    // Implementation that utilizes the provided service and cache.
}

ICacheパラメーターに注目してください。この概念はドメインの一部ではないため、ドメインサービスではありません。それはアプリケーションサービスです。これは、アプリケーションによって提供されるインフラストラクチャの依存関係です。これを実証するアプリケーションを紹介しましょう。

私のソリューション
- My.Product.Core (My.Product.dll)
-DomainServices 
 IExchangeRateService 
 Product 
 ProductFactory 
 IProductRepository 
- My.Product.Infrastructure (My.Product.Infrastructure.dll)
-ApplicationServices 
 ICache 
-DomainServices 
 CachingExchangeRateService 
 XEExchangeRateService 
 SqlServerProductRepository 
- My.Product.WcfService (My.Product.WcfService.dll)
-ApplicationServices 
 MemcachedCache 
 IMyWcfService.cs 
 + MyWcfService.svc 
 + Web.config 

これらはすべて、次のようにアプリケーションにまとめられます。

// Set up all the dependencies and register them in the IoC container.
var service = new XEExchangeRateService();
var cache = new MemcachedCache();
var cachingService = new CachingExchangeRateService(service, cache);

ServiceLocator.For<IExchangeRateService>().Use(cachingService);

概要

完全なアプリケーションは、3つの主要な層で構成されます。

  • ドメイン
  • インフラ
  • 応用

ドメイン層には、ドメインエンティティとスタンドアロンドメインサービスが含まれます。外部リソースに依存するすべてのドメインコンセプト(これにはドメインサービスだけでなくリポジトリも含まれます)は、インターフェースによって定義されます。

インフラストラクチャ層には、ドメイン層からのインターフェースの実装が含まれています。これらの実装は、アプリケーションに提供する必要がある新しいnon-domain依存関係を導入する場合があります。これらはアプリケーションサービスであり、インターフェイスによって表されます。

アプリケーション層には、アプリケーションサービスの実装が含まれています。インフラストラクチャ層によって提供される実装が十分でない場合、アプリケーション層にはドメインインターフェイスの追加の実装も含まれる場合があります。

この観点はサービスの一般的なDDD定義と一致しない場合がありますが、ドメインをアプリケーションから分離し、複数のアプリケーション間でドメイン(およびインフラストラクチャ)アセンブリを共有できます。

106

アプリケーションサービスとドメインサービスの違いを理解するのに役立った最良のリソースは、エリックエバンスの貨物サンプルのJava実装でした here が見つかりました。ダウンロードしない場合、RoutingService(ドメインサービス)とBookingService、CargoInspectionService(アプリケーションサービス)の内部をチェックアウトできます。

私の 'aha'の瞬間は、2つのことによって引き起こされました。

  • 上記のリンク、より正確にはこの文のサービスの説明を読む:

ドメインサービスは、ユビキタス言語とドメインタイプで表現されます。つまり、メソッドの引数と戻り値は適切なドメインクラスです。

リンゴとオレンジを分離する上で大きな助けとなるのは、アプリケーションワークフローの観点から考えることです。通常、アプリケーションワークフローに関するすべてのロジックは、アプリケーション層に含まれるアプリケーションサービスになりますが、モデルオブジェクトとして適合しないドメインの概念は、1つ以上のドメインサービスを形成します。

35
Ghola

Red Book(Implementing Domain Driven Design、Vaughn Vernon著)から、これが概念の理解方法です。

ドメインオブジェクトエンティティおよび値オブジェクト)(サブ)ドメインに必要な動作をカプセル化し、自然で表現力豊かで理解しやすいものにします。

ドメインサービスsingleドメインオブジェクトに収まらないような動作をカプセル化します。たとえば、BookClientに貸し出している本ライブラリ(対応するInventoryの変更を含む)は、ドメインサービスから行うことができます。

アプリケーションサービスユースケースのフローを処理し、必要な追加の懸念事項を含めます上にドメインの。多くの場合、外部クライアントが使用するために、APIを介してこのようなメソッドを公開します。前の例を基にして、アプリケーションサービスは次のメソッドLendBookToClient(Guid bookGuid, Guid clientGuid)を公開します。

  • Clientを取得します。
  • その許可を確認します。 (ドメインモデルをセキュリティ/ユーザー管理の懸念から解放したことに注意してください。このような汚染は多くの問題につながる可能性があります。代わりに、アプリケーションサービスでこの技術要件を満たします。
  • Bookを取得します。
  • ドメインサービスを呼び出して(ClientおよびBookを渡して)実際のドメインロジッククライアントへの本の貸し出しを処理します。たとえば、本の入手可能性を確認することは、ドメインロジックの一部であることは間違いないと思います。

一般に、アプリケーションサービスには非常に単純なフローが必要です。複雑なアプリケーションサービスフローは、多くの場合、ドメインロジックがドメイン外に漏れていることを示しています。

ご覧のとおり、ドメインモデルは非常にcleanのままで、ドメインの専門家と簡単に理解して議論できます。懸念。一方、アプリケーションフローalsoにより管理がはるかに簡単です。これは、ドメインの懸念が軽減され、簡潔で簡単になるためです。

27
Timo

ドメインサービスはドメインの拡張子です。ドメインのコンテキストでのみ表示されます。これは、たとえばclose accountなどのユーザーアクションではありません。ドメインサービスは、状態がない場合に適合します。それ以外の場合は、ドメインオブジェクトになります。ドメインサービスは、他の共同作業者(ドメインオブジェクトまたは他のサービス)を使用する場合にのみ意味のあることを行います。そして、意味をなすことは、別の層の責任です。

アプリケーションサービスは、ドメインオブジェクトとサービス間の相互作用を初期化および監視するレイヤーです。フローは一般的に次のようになります:リポジトリからドメインオブジェクトを取得し、アクションを実行して、そこに戻す(またはしない)。さらに多くのことができます-たとえば、ドメインオブジェクトが存在するかどうかを確認し、それに応じて例外をスローできます。したがって、ドメインオブジェクトとサービスを操作することで、ユーザーがアプリケーションと対話できるようにします(これはおそらくその名前の由来です)。通常、アプリケーションサービスは、可能なすべてのユースケースを表す必要があります。ドメインについて考える前にできる最善のことは、アプリケーションサービスインターフェイスを作成して、実際に何をしようとしているのかをよりよく理解することです。このような知識があると、ドメインに集中できます。

リポジトリは一般的にドメインサービスに挿入できますが、これはかなりまれなシナリオです。ほとんどの場合、それを行うのはアプリケーション層です。

24
kboom

ドメインサービス:単一のエンティティに実際には適合しないメソッド、またはリポジトリへのアクセスが必要なメソッドは、ドメインサービスに含まれています。ドメインサービス層には、独自のドメインロジックを含めることもでき、エンティティや値オブジェクトと同じくらいドメインモデルの一部です。

アプリケーションサービス:アプリケーションサービスは、ドメインモデルの上にあり、アプリケーションアクティビティを調整する薄い層です。ビジネスロジックが含まれておらず、エンティティの状態を保持していません。ただし、ビジネスワークフロートランザクションの状態は保存できます。アプリケーションサービスを使用して、Request-Replyメッセージングパターンを使用して、ドメインモデルにAPIを提供します。

ミレット、C(2010)。プロフェッショナルなASP.NETデザインパターン。ワイリー出版。 92。

8
GorkemHalulu

ドメインサービス:集約ルートの一部ではないビジネスロジックを表現するサービス。

  • 2つの集計があります:

    • Productには名前と価格が含まれます。
    • Purchaseには、購入日、その時点での数量と製品価格で注文された製品のリスト、および支払い方法が含まれます。
  • Checkoutは、これら2つのモデルのいずれの一部でもなく、ビジネスの概念です。

  • Checkoutは、すべての製品を取得して合計価格を計算し、インフラストラクチャの実装部分で別のドメインサービスPaymentServiceを呼び出して合計を支払い、それをPurchaseに変換するドメインサービスとして作成できます。

アプリケーションサービス "orchestrates"またはドメインメソッドを実行するサービス。これは、コントローラーと同じくらい簡単です。

これは通常あなたがする場所です:

public String createProduct(...some attributes) {
  if (productRepo.getByName(name) != null) {
    throw new Exception();
  }

  productId = productRepository.nextIdentity();

  product = new Product(productId, ...some attributes);

  productRepository.save(product);

  return productId.value();
  // or Product itself
  // or just void if you dont care about result
}

public void renameProduct(productId, newName) {
  product = productRepo.getById(productId);

  product.rename(newName);

  productRepo.save(product);
}

ここで、Productが一意であるかどうかを確認するなどの検証を行うことができます。一意であるProductが不変式でない限り、それはUniqueProductCheckerクラスの一部とすることはできず、複数の集合体と対話するため、Productと呼ばれるドメインサービスの一部である必要があります。

DDDプロジェクトの本格的な例を次に示します。 https://github.com/VaughnVernon/IDDD_Samples

Application Serviceの例といくつかのDomain Serviceの例を見つけることができます

2
doesnotmatter