回答:
サービスには、ドメインサービス、アプリケーションサービス、インフラストラクチャサービスの 3つの種類があります。
ドメインサービスをドメインオブジェクトと一緒に維持することは賢明です。これらはすべてドメインロジックに重点を置いています。そしてはい、あなたはあなたのサービスにリポジトリを注入することができます。
アプリケーションサービスは通常、ドメインサービスとリポジトリの両方を使用して外部リクエストを処理します。
お役に立てば幸いです。
(読みたくない場合は、下部に概要があります:-)
私も、アプリケーションサービスの正確な定義に苦労しています。Vijayの答えは1か月前の私の思考プロセスに非常に役立ちましたが、私はそれの一部に同意しなくなりました。
アプリケーションサービスに関する情報はほとんどありません。集約ルート、リポジトリ、ドメインサービスなどのテーマについては幅広く説明されていますが、アプリケーションサービスについては簡単に説明するか、まったく省略しています。
MSDNマガジンの記事「ドメイン駆動設計の概要」では、ドメインサービスをWCFサービスなどの外部クライアントに変換および/または公開する方法として、アプリケーションサービスについて説明しています。これは、Vijayがアプリケーションサービスについても説明する方法です。この観点から見ると、アプリケーションサービスはドメインへのインターフェースです。
オニオンアーキテクチャ上のジェフリー・パレルモの記事(パート1、2と3は)良い読み物です。彼は、アプリケーションサービスを、ユーザーのセッションなどのアプリケーションレベルの概念として扱います。これはアプリケーションサービスについての私の理解により近いものですが、それでも、このテーマに関する私の考えと一致していません。
アプリケーションサービスは、アプリケーションによって提供される依存関係と考えるようになりました。この場合、アプリケーションはデスクトップアプリケーションまたはWCFサービスです。
例の時間。ドメインから始めます。外部リソースに依存しないすべてのエンティティとドメインサービスがここに実装されます。外部リソースに依存するドメインの概念は、インターフェースによって定義されます。以下は可能なソリューションレイアウトです(太字のプロジェクト名)。
私の解決策 - My.Product.Core(My.Product.dll) -DomainServices IExchangeRateService 製品 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 製品 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つの主要な層で構成されています。
ドメイン層には、ドメインエンティティとスタンドアロンドメインサービスが含まれます。外部リソースに依存するドメインの概念(ドメインサービスだけでなくリポジトリも含まれます)は、インターフェースによって定義されます。
インフラストラクチャ層には、ドメイン層からのインターフェースの実装が含まれています。これらの実装では、アプリケーションに提供する必要がある新しい非ドメイン依存関係が導入される場合があります。これらはアプリケーションサービスであり、インターフェイスによって表されます。
アプリケーション層には、アプリケーションサービスの実装が含まれます。インフラストラクチャ層によって提供される実装が十分でない場合は、アプリケーション層にドメインインターフェイスの追加の実装が含まれる場合もあります。
この視点は、サービスの一般的なDDD定義と一致しない場合がありますが、アプリケーションからドメインを分離し、複数のアプリケーション間でドメイン(およびインフラストラクチャ)アセンブリを共有できるようにします。
IExchangeRateService
インターフェースのことですか?これはドメインの概念です。つまり、顧客のユビキタス言語に含まれているものです。ドメインの他の部分はこのサービスに依存している可能性があります。そのため、そのインターフェースはドメイン層で定義されています。ただし、その実装には外部Webサービスが含まれるため、実装クラスはインフラストラクチャ層に存在します。このように、ドメイン層はビジネスロジックのみに関係しています。
ExchangeRate
インスタンスである可能性があります。これには、基本通貨、カウンター通貨、およびこれら2つの通貨間の為替レート値が含まれます。これらの密接に関連する値は、ドメインからの「為替レート」の概念を表すため、これらはドメインレイヤーに存在します。単純なDTOのように見えますが、DDDでは値オブジェクトと呼ばれ、インスタンスを比較または変換するための追加のビジネスロジックを含めることができます。
アプリケーションサービスとドメインサービスの違いを理解するのに役立つ最高のリソースは、ここにあるエリックエバンスの貨物サンプルのJava実装でした。ダウンロードすると、RoutingService(ドメインサービス)とBookingService、CargoInspectionService(アプリケーションサービス)の内部をチェックアウトできます。
私の「あは」の瞬間は2つのことによって引き起こされました。
上記のリンクのサービスの説明、より正確にはこの文を読む:
ドメインサービスは、ユビキタス言語とドメインタイプで表現されます。つまり、メソッドの引数と戻り値は適切なドメインクラスです。
このブログ記事、特にこの部分を読む:
リンゴをオレンジから分離するのに大きな助けとなるのは、アプリケーションワークフローの観点から考えています。アプリケーションワークフローに関するすべてのロジックは通常、アプリケーションレイヤーに組み込まれるアプリケーションサービスになりますが、モデルオブジェクトとして適合しないように見えるドメインの概念は、1つ以上のドメインサービスを形成します。
ドメインサービスは、ドメインの拡張です。ドメインのコンテキストでのみ表示されます。これは、たとえばアカウントの閉鎖などのユーザーアクションではありません。ドメインサービスは、状態がない場所に適合します。それ以外の場合は、ドメインオブジェクトになります。ドメインサービスは、他の共同作業者(ドメインオブジェクトまたは他のサービス)で行われる場合にのみ意味のあることを行います。そしてその意味は別のレイヤーの責任です。
アプリケーションサービスは、ドメインオブジェクトとサービス間の相互作用を初期化および監視する層です。フローは通常、次のようなものです。リポジトリからドメインオブジェクト(またはオブジェクト)を取得し、アクションを実行して、そこに(それらを)戻します(または戻さない)。より多くのことができます。たとえば、ドメインオブジェクトが存在するかどうかを確認し、それに応じて例外をスローできます。したがって、ドメインオブジェクトとサービスを操作することで、ユーザーはアプリケーションと対話できます(これはおそらく、その名前の由来です)。アプリケーションサービスは通常、考えられるすべてのユースケースを表す必要があります。おそらく、ドメインについて考える前にできる最善のことは、実際に何をしようとしているのかについてより良い洞察を提供するアプリケーションサービスインターフェイスを作成することです。このような知識があると、ドメインに集中できます。
リポジトリは一般的に言えばドメインサービスに注入できますが、これはかなりまれなシナリオです。ほとんどの場合それを行うのはアプリケーション層です。
Red Book(Vaughn Vernonによるドメイン駆動設計の実装)から、これは私が概念を理解する方法です:
ドメインオブジェクト(エンティティおよび値オブジェクト)は、(サブ)ドメインに必要な動作をカプセル化し、自然で表現力豊かで理解しやすいものにします。
ドメインサービスは、単一のドメインオブジェクトに適合しないそのような動作をカプセル化します。例えば、融資ブックライブラリBook
にClient
(対応してInventory
変化)は、ドメインサービスからそうかもしれません。
アプリケーションサービスは、ドメインに加えて必要な追加の懸念事項を含む、ユースケースのフローを処理します。外部クライアントが使用するために、APIを介してそのようなメソッドを公開することがよくあります。前の例を基にして、アプリケーションサービスは次のメソッドLendBookToClient(Guid bookGuid, Guid clientGuid)
を公開する場合があります。
Client
ます。Book
ます。Client
およびを渡すBook
)、本をクライアントに貸す実際のドメインロジックを処理します。たとえば、本の入手可能性を確認することは間違いなくドメインロジックの一部だと思います。アプリケーションサービスは、通常、非常に単純なフローである必要があります。複雑なアプリケーションサービスフローは、ドメインロジックがドメインの外にリークしたことを示していることがよくあります。
うまくいけばわかるように、ドメインモデルはこのように非常にクリーンなままであり、ドメインの専門家と簡単に理解および議論できます。これは、独自の実際のビジネス上の懸念のみが含まれているためです。アプリケーションフローは、他の一方で、あるにもそれはドメイン上の問題から解放されるため、管理がはるかに容易に、かつ簡潔、かつ簡単になります。
ドメインサービス:単一のエンティティに実際には適合しない、またはリポジトリへのアクセスを必要とするメソッドは、ドメインサービス内に含まれます。ドメインサービスレイヤーには、独自のドメインロジックを含めることもでき、エンティティや値オブジェクトと同じくらいドメインモデルの一部です。
アプリケーションサービス:アプリケーションサービスは、ドメインモデルの上に配置され、アプリケーションアクティビティを調整する薄いレイヤーです。ビジネスロジックが含まれておらず、エンティティの状態を保持していません。ただし、ビジネスワークフロートランザクションの状態を保存できます。アプリケーションサービスを使用して、Request-Replyメッセージングパターンを使用するAPIをドメインモデルに提供します。
ミレット、C(2010)。プロフェッショナルASP.NETデザインパターン。ワイリー出版。92。
ドメインサービス:集約ルートの一部ではないビジネスロジックを表現するサービス。
2つの集計があります:
Product
名前と価格が含まれています。Purchase
これには、購入日、その時点で注文された製品の数量と価格、および支払方法のリストが含まれています。Checkout
はこれら2つのモデルのいずれにも含まれておらず、ビジネスのコンセプトです。
Checkout
すべての製品を取得して合計金額を計算し、PaymentService
インフラストラクチャの実装部分を使用して別のドメインサービスを呼び出して合計を支払い、それをに変換するドメインサービスとして作成できますPurchase
。アプリケーションサービス:ドメインメソッドを「オーケストレーション」または実行するサービス。これは、コントローラーと同じくらい簡単です。
これは通常行う場所です。
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の例を見つけることができます
ドメインサービスを、ビジネスロジックまたはビジネスルール関連のロジックをドメインオブジェクトに実装するオブジェクトと考えてください。このロジックは、同じドメインオブジェクトに適合させることが難しく、ドメインサービスの状態変更を引き起こしません(ドメインサービスは、ビジネス上の意味を持つ状態がない「状態」以上)が、最終的には操作対象のドメインオブジェクトの状態のみを変更します。
一方でアプリケーションサービスの認証、セキュリティ、電子メールで送信する、というように..単にドメインオブジェクトによって公開されるサービスを使用するために自分自身を制限:ユーザーとの対話、入力検証、ロジック事業ではなく、他の懸念に関連していないとして実装応用的レベルのロジック。
この例としては、目的を説明するためだけに考えられた次のシナリオが考えられます。「誰かが家の部屋のドアを開いて入るときに、ライトをオンにする」という単純な操作を実行する非常に小さなdomoticユーティリティアプリを実装する必要があります部屋から出るドアを閉めると、ライトが消えます。」
単純化するのは2つのドメインエンティティだけです。Door
そしてLamp
、それぞれに2つの状態があり、それぞれopen/closed
とon/off
、およびそれらの状態の変更を操作する特定のメソッドがあります。
この場合、ドアとランプオブジェクトが適切と考える方法でこのロジックを実装できないため、誰かがドアを外側から開いて部屋に入るときに、ライトをオンにする特定の操作を実行するドメインサービスが必要です。その性質に。
ドメインサービスをとして呼び出し、DomoticDomainService
2つのメソッドを実装できます。OpenTheDoorAndTurnOnTheLight
そしてCloseTheDoorAndTurnOffTheLight
、これらの2つのメソッドは、オブジェクトDoor
とLamp
to open/on
およびの両方の状態をそれぞれ変更しますclosed/off
。
部屋への入室または退室の状態は、ドメインサービスオブジェクトにもドメインオブジェクトにも存在しませんが、アプリケーションサービスによって単純なユーザー操作として実装されHouseService
ます。onOpenRoom1DoorToEnter
、、などonCloseRoom1DoorToExit
、各部屋(これは目的を説明するための例にすぎません。)は、それぞれ、呼び出しドメインサービスメソッドが関与する動作を実行することに関係します(Room
例にすぎないため、エンティティは考慮していません)。。
この例は、十分に設計された実際のアプリケーションとは言えませんが、ドメインサービスとは何か、アプリケーションサービスとの違いを説明することだけを目的としています(何度も言っています)。