サービスレイヤーまたはドメインオブジェクト自体とのインターフェイス? (DDD)
-
29-09-2019 - |
質問
私はまだDDDについて学んでおり、これら2つの(おそらく簡単な)質問があります。
もし 工場 新しいオブジェクト/グラフを作成/集計 インスタンスだけでなく 「再構成」 からのオブジェクト/グラフ リポジトリ, 、 それから:
(1)サービスレイヤーは、工場への機能/ジョブ/タスク/作業単位呼び出しまたはエンティティインスタンスまたはドメインサービス関数の行動方法への呼び出しですか?これらのコンポーネントの責任に基づいて、コールスタックに迷っています。
(2)エンティティインスタンスは、上記のような「行動方法」さえ持っていますか?たとえば、投稿にはあります p.UpdatePost(string bodyText)
または、それはドメインモデルの懸念ではないので、リポジトリでも同じことを達成する必要がありますか?または、サービスレイヤー関数は、この場合はリポジトリを呼び出す必要があり、エンティティインスタンスには、持続性ではなくドメインに固有の行動方法がありますか?しかし、その後、なぜ「投稿の更新」がユーザーの目標であるときにドメイン関数であるように聞こえるのですか?
あなたは私があちこちにいるのを見ることができます。助けてください。
解決
(1)サービスレイヤーは、工場への機能/ジョブ/タスク/作業単位呼び出しまたはエンティティインスタンスまたはドメインサービス関数の行動方法への呼び出しですか?これらのコンポーネントの責任に基づいて、コールスタックに迷っています。
通常 - トップレベルは必要な集計ルートを取得し、その上の関数を呼び出します。トップレベルが複数の総根を取得してドメインサービスに渡すことがありますが、ドメインサービスが認識されていない集計ルートがあることを非常に強力な兆候であるため、頻繁にはありません。最後に、トップレベルが集合ルートが持続することを保証します。
(2)エンティティインスタンスは、上記のような「行動方法」さえ持っていますか?たとえば、投稿にはp.updatePost(string bodytext)がありますか、それともドメインモデルの懸念ではないので、リポジトリでも同じことを達成する必要がありますか?または、サービスレイヤー関数は、この場合はリポジトリを呼び出す必要があり、エンティティインスタンスには、持続性ではなくドメインに固有の行動方法がありますか?しかし、その後、なぜ「投稿の更新」がユーザーの目標であるときにドメイン関数であるように聞こえるのですか?
はい、彼らはやる。ドメインモデルは、その状態の変更に注意する必要があります。そして、それは最初ははるかに有益です。これについて素晴らしいことは、拡張性ポイントを獲得することです。クライアントが1週間後にあなたに向かって歩き、ユーザーの更新が投稿されたときに追加のものをチェックしてほしいと言っている場合 - すべての行を検索する代わりに post.bodyText="new value"
, 、あなたはまっすぐに行くことができるでしょう post.UpdatePost
メソッドとそこに必要なものを添付します。
一方、CRUDはドメイン駆動型のデザインで相互に排他的ではありません。たとえば、私のアプリケーションでは、ユーザーの管理とその役割は十分に面白くないので、それをきめ細かくモデル化しようとさえしません。あなたのアプリケーションが説明し、協力しているビジネスで重要なことをパーツを認識する必要があります。
ドメイン駆動型の設計は、複雑なアプリケーションのみに理にかなっていることに注意してください。簡単なブログアプリケーションは必要ありません。
(3)サービスレイヤー(ドメインサービスではない)がインターフェイスがドメインレイヤーとどのように相互作用するかをカプセル化する必要があると仮定するのは間違っていますか?
私が見るように、アプリケーションサービスはインフラストラクチャを調整するためのより多くのものです。インフラストラクチャが関係していない場合 - アプリケーションサービス 価値を失います:
アプリケーションサービスは基本的に単なるファサードです。そして、それが解決する太りすぎの問題を追加する複雑さの場合、すべてのファサードは悪いです。
内部ドメイン:
//aggregate root is persistence ignorant.
//it shouldn't reference repository directly
public class Customer{
public string Name {get; private set;}
public static Customer Register(string name){
return new Customer(name);
}
protected Customer(string name){
//here it's aware of state changes.
//aggregate root changes it's own state
//instead of having state changed from outside
//through public properties
this.Name=name;
}
}
//domain model contains abstraction of persistence
public interface ICustomerRepository{
void Save(Customer customer);
}
ドメインの外:
public class CustomerRepository:ICustomerRepository{
//here we actually save state of customer into database/cloud/xml/whatever
public void Save(Customer customer){
//note that we do not change state of customer, we just persist it here
_voodoo.StoreItSomehow(customer);
}
}
//asp.net mvc controller
public class CustomerController{
public CustomerController(ICustomerRepository repository){
if (repository==null)throw new ArgumentNullException();
_repository=repository;
}
public ActionResult Register(string name){
var customer=Customer.Register(name);
_repository.Save(customer);
}
}