7

1)ドメイン レイヤーがインフラストラクチャ サービス ISを使用している場合、そのインターフェイスはドメイン レイヤー内で定義され、その実装はインフラストラクチャ レイヤー内で定義されます。

IS (リポジトリや電子メール サービスなど) をドメイン エンティティに直接挿入するべきではありません。

class Foo
{
       IRepository repo;
           ...
       public int DoSomething()
       {
            var info = repo.Get...;
              ...
       }
}

代わりに、ドメイン エンティティの何らかのメソッドが特定のISを必要とする場合、アプリケーション レイヤーはそのISを引数としてそのメソッドに渡すことができます。

 class Foo
{
           ...
       public int DoSomething(IRepository repo)
       {
            var info = repo.Get...;
              ...
       }
}

a) ISもDomain Servicesに直接注入すべきではないと思います:

class TransferService
{
         IRepository repo;
             ...
         public bool Transfer()
         {
            var info = repo.Get...;
              ...
         } 
} 

、代わりにISを使用するドメイン サービスのメソッドに引数として渡す必要があります。

class TransferService
{
         public bool Transfer(IRepository repo)
         {
            var info = repo.Get...;
              ...
         } 
} 

b)ドメインエンティティのメソッドがドメインサービスを使用する必要がある場合、引数を介してそれを受け取る必要はないと思います(ドメインサービスを引数として渡すと、メソッドの依存関係を明示的に伝えるという利点があります)が、代わりに呼び出すことができますドメインエンティティドメインサービスの両方がドメインの概念であるためです。

class Foo
{
       ...

       public int DoSomething()
       {
            var info = TransferService.Transfer(...);
              ...
       }
}

アップデート:

1)

機能のために IS が必要な場合は、IS をドメイン サービスに挿入できます。つまり、メソッドに渡されません。これはエンティティとは異なります。これは、ドメイン サービスがステートレスであるため、必要な依存関係を一度構成して、必要な場所 (他のエンティティなど) で使用できるためです。

a)ドメイン エンティティにISを注入してはならない主な理由は、そのステートフルな性質によるものですか?

b) しかし、ドメイン エンティティにISを注入しない主な理由は、持続性無視ルールに違反するからだと思いましたか?

c) ISを注入した場合、エンティティのステートフルな性質はどのような問題を引き起こしますか?

d)ドメイン サービスにISを挿入することは PI に違反しませんか? そうでない場合、なぜですか?

2)

ドメイン サービスは、リポジトリ インターフェイスを引数として渡すのと同じように、引数としてエンティティに渡す必要があります。同じ原則が適用されます。

しかし、リポジトリとは異なり、ドメイン サービスはドメインの概念です。「同じ原則が適用される」とはどういう意味ですか? つまり、Domain ServiceDomain Entityに注入してもPIに違反しませんが、 Repositoryを注入してもPI に違反します!

2 番目の更新:

1)

a)

それが一つの理由です。もう 1 つは、不必要なカップリングを作成することです。エンティティの 1 つの動作だけにリポジトリが必要な場合、それを常にエンティティに挿入するのはなぜでしょうか? また、これらの依存関係を解決する方法を検討する必要がありますか? エンティティを依存性注入グラフの一部にしますか? これにより、エンティティの責任が急速に過負荷になります。

したがって、私の理解が正しければ、ISドメイン サービス DSに挿入しても SRP に違反しません。これは、 DSが指定されたタスク (つまり、指定された責任) を実行するためにそれを使用しているためです。一方、ドメイン エンティティにISを挿入することは、主な責任であるため、SRP に違反しています。のドメイン エンティティはそのライフ サイクルとアイデンティティに焦点を当てていますが、ほとんどの場合、ISはこれら 2 つのタスクを管理する上で不可欠な部分ではありません (つまり、ライフ サイクルとアイデンティティに焦点を当てています)。

b)

IS をドメイン エンティティ メソッドに渡すことはできますが、実装ではなくインターフェイスを渡しているため、ここでの問題は PI の違反にはなりません。ドメイン メソッドが IS インターフェイスで 1 つのメソッドしか使用しない場合、問題は SRP 違反になります。

I - しかし、以前の投稿のいくつかで、 ISをDomain Entityのメソッドに引数として渡しても問題ないと述べていましたが、ここでは、このドメイン メソッドがISインスタンスで 1 つのメソッドのみを使用すると、SRP に違反するとおっしゃっていますか?

II - ISが単一のメソッドを含む役割ベースのインターフェースを実装し、代わりにこの役割ベースのインターフェースをドメイン メソッドの引数として渡す場合、これを SRP 違反とみなしますか? そうでない場合、なぜですか?

d)

PI はインターフェイスを使用して維持されます。

ドメインメソッドがインターフェースを介してリポジトリを参照している場合でも、PI の違反と見なされることを何度か読みました。なぜそれに同意しないのですか?

2)

ただし、非常に明示的である方がよいでしょう。したがって、リポジトリを渡してエンティティにサービスを提供することを暗黙のうちに理解する代わりに、提供された機能を独自のインターフェイスとして宣言し、エンティティがそれに依存するようにします。

a) それでは、ドメイン サービスドメイン エンティティに注入しない唯一の理由は、SRP の違反によるものですか?

b)

提供された機能を独自のインターフェースとして宣言する

ロールベースのインターフェースを使用することを提案していると思いますか? しかし、役割ベースのインターフェイス (たとえば Domain Service によって実装されたもの) を Domain Entity に注入してもSRP違反発生することはありません。 !

ドメイン エンティティのメソッドにISを渡すことに関して、あなたと Aaron Hawkins は反対側にいるようです ?!

3 番目の更新:

1)

a)

したがって、私の理解が正しければ、IS をドメイン サービス DS に挿入しても SRP に違反しません。これは、DS が指定されたタスク (つまり、指定された責任) を実行するためにそれを使用しているためです。一方、ドメイン エンティティに IS を挿入することは、主な責任であるため、SRP に違反しています。ドメイン エンティティのほとんどは、そのライフ サイクルとアイデンティティに焦点を当てていますが、ほとんどの場合、これら 2 つのタスクを管理する上で不可欠な部分ではありません (つまり、ライフ サイクルとアイデンティティに焦点を当てています)。

はい、それは正しく、主な理由の 1 つです。

I - ISドメイン エンティティ DEに挿入することによって、このDEが SRP に違反することは完全に合理的に思えます。なぜなら、 ISはDEに指定された 2 つのタスクの管理に貢献しないからです。

しかし、このシナリオをより詳細に想像しようとすると、少し難しくなります。つまり、DEのメソッドが2 つの指定されたタスク (つまり、そのライフサイクルとアイデンティティ) の管理に焦点を当てている場合、これらのメソッドのいずれかがISを必要とする場合、2 つの指定されたタスクを達成するためにISが必要であると仮定するのは合理的ではないでしょうか? DE のライフ サイクルと IDに関係のない他のタスクではありませんか? はいの場合、 DEが SRP に違反しているとどのように主張できますか?

II - DE のライフ サイクルと IDを管理することの正確な意味を想像するのも困難です。まず、DEに ID が割り当てられると、この ID は変更されません。では、そのアイデンティティについてはどう管理する必要があるのでしょうか?

III - DE のライフサイクルを管理するとはどういう意味ですか? おそらく、データの一貫性を保つDEの不変条件を定義するか...?

IV - 実世界のエンティティが実行する他のすべてのタスク (つまり、DE のライフ サイクルと ID に関連しないもの) は、DEから除外して関連オブジェクトに入れる必要がありますか?

d)

IS が 1 つのメソッドを含む役割ベースのインターフェイスを実装し、代わりにこの役割ベースのインターフェイスをドメイン メソッドの引数として渡す場合、これを SRP 違反と見なしますか? そうでない場合、なぜですか?

それを行うのはひどいことではありませんが、SRP に違反する可能性があります。

ISDEに挿入するとISPに違反する可能性があるとどのように主張できるかわかりません。私の知る限り、 ISPはこのインターフェイスを実装するオブジェクトによってのみ違反される可能性があり、このインターフェイスの実装が挿入されるオブジェクトによって違反される可能性があるからです。

4 回目の更新:

SRP は当初考えていたよりもはるかに複雑であることに気付き始めています

a)

通常は状態の変更を伴うエンティティに関連付けられた動作も、エンティティに配置する必要があります。そのような動作でサービスを使用する必要がある場合は、そのサービスを渡しますが、通常はエンティティにできるだけ多くの動作を配置するようにします。

DogIV – 1 次の動作メソッドには状態の変更は含まれていませんが、それらもエンティティに属する必要があると思います。

class Dog
{
            ...
       void DoBark();
       void DoFetch();
       void DoGuard();

       Breed    GetBreed();
       Pedigree GetPedigree();
       Snack    FavSnack();
}

IV – b)および行動方法GetBreedは? はいの場合、プロパティ、およびも動作と見なす必要があります。これらは本質的に同じ機能を提供するためです ( 、および重い計算を行わず、単にオブジェクトを返すと仮定します) 。GetPedigreeFavSnackBreedPedigreeSnackGetBreedGetPedigreeFavSnack

class Dog
{
            ...
       void DoBark();
       void DoFetch();
       void DoGuard();

       Breed    Breed { get{...} }
       Pedigree Pedigree { get{...} }
       Snack    Snack { get{...} }
}

IV – c) 上記のプロパティにもsetterがある場合、それらには状態変更動作が含まれていると言えますか?

IV – d)

通常は状態の変更を伴うエンティティに関連付けられた動作も、エンティティに配置する必要があります。

しかし、ドメイン エンティティの主な責任がそのライフ サイクルの管理である場合、ライフ サイクルの管理に関係のない動作を含めないことは、SRP の違反になります (上記の例でDog.DoBarkは、Dog「のライフサイクル)?!

d)

私。

IS を DE ビヘイビア メソッドに渡す方が優れていますが、IS インターフェイスに目前のビヘイビアに関係のないものがたくさんある場合、SRP/ISP に違反する可能性があります。これは ISP の基本的な前提です。依存関係は、たまたま必要な機能を含む肥大化したインターフェイスとは対照的に、特定のインターフェイスに作成する必要があります。

そのため、ISが DE の動作メソッドの 1 つに引数として渡された場合、目の前の動作に関係のない操作がいくつかありますが、DE のメソッドMは、 Mが処理する必要がある動作に関係のないISのメソッドを使用しません。 SRP/ISP に違反していませんか?

Ⅱ.– あなたの言っていることは理解できますが、次の ISP の定義によれば、この用語は、特定のインターフェースを実装するオブジェクトServObjが ISP に違反していることを示すためにのみ使用されるべきであるという事実から、私の混乱が生じます注入されたのは SRP に違反しています ( ServObjを受け取ったため):

インターフェイス分離の原則は、責任の結合を扱うという点で単一責任の原則に似ています。実際、ISP は、オブジェクトのパブリック インターフェイスへの SRP のアプリケーションとして理解できます。

ISP は、ある程度、単一責任原則のサブセット、またはより具体的な形態と見なすことができます。ただし、ISP の見方の変化は、特定のクラスまたはモジュールのパブリック API を調べます。

ありがとうございました

4

2 に答える 2

6

1a) 機能のために IS が必要な場合は、IS をドメイン サービスに挿入できます。つまり、メソッドに渡されません。これはエンティティとは異なります。これは、ドメイン サービスがステートレスであるため、必要な依存関係を一度構成して、必要な場所 (他のエンティティなど) で使用できるためです。

1b) リポジトリ インターフェイスを引数として渡すのと同じように、ドメイン サービスを引数としてエンティティに渡す必要があります。同じ原則が適用されます。また、リポジトリ インターフェイス全体を渡すと、不要な結合が作成される可能性があるため、ロール固有のインターフェイスを宣言して渡すことをお勧めします。

アップデート

1a) それが一つの理由です。もう 1 つは、不必要なカップリングを作成することです。エンティティの 1 つの動作だけにリポジトリが必要な場合、それを常にエンティティに挿入するのはなぜでしょうか? また、これらの依存関係を解決する方法を検討する必要がありますか? エンティティを依存性注入グラフの一部にしますか? これにより、エンティティの責任が急速に過負荷になります。

1b) PI の違反は、単一責任の原則に違反するというより一般的な概念の例です。IS をドメイン エンティティ メソッドに渡すことはできますが、実装ではなくインターフェイスを渡しているため、ここでの問題は PI 違反にはなりません。ドメイン メソッドが IS インターフェイスで 1 つのメソッドしか使用しない場合、問題は SRP 違反になります。

1c) 1a)を参照

1d) インターフェースを使用して PI が維持されるため、いいえ。

2) はい。そのため、リポジトリ インターフェイスを直接渡さないようにすることをお勧めします。リポジトリ インターフェースとドメイン サービスの両方を、ドメイン エンティティにとって興味深い動作を提供する抽象的なサービスと考えることができるため、原則は似ています。ただし、非常に明示的である方がよいでしょう。したがって、リポジトリを渡してエンティティにサービスを提供することを暗黙のうちに理解する代わりに、提供された機能を独自のインターフェイスとして宣言し、エンティティがそれに依存するようにします。

更新 2

1a) はい、それは正しく、主な理由の 1 つです。

1b) それはひどいことではありませんが、SRP に違反する可能性があります。したがって、エンティティ インスタンスに注入すると言うよりはましですが、特定のインターフェイスを宣言することで改善される可能性があります。

いいえ、役割ベースのインターフェイスを作成する場合、これはこのシナリオで得られるのと同じくらい優れています。

1d) エンティティがリポジトリ インターフェースを使用して自身を存続させる場合、これは PI 違反です。ただし、ビジネス ロジックを実行するためにリポジトリ インターフェイスを使用して何らかのクエリを実行する場合、実際には永続性について話しているわけではありません。リポジトリを実際に切り離すには、代わりにロール固有のインターフェイスを使用します。

2a) はい。同じ理由で、リポジトリをエンティティに挿入することは適切ではありません。

2b) はい。ただし、エンティティ インスタンス自体にドメイン サービスを注入するのではなく、ドメイン サービスをエンティティの動作メソッドに渡すシナリオでのみ提案しています。

更新 3

1a) これは論点になる可能性がありますが、私は同意します。ただし、実用的な観点からは、DE の外部サービスへの依存が排除されるか、非常に明示的かつ分離されるように DE を設計することをお勧めします。DE のインスタンスが IS に依存している場合、再構成時や新しいエンティティの作成時など、DE のインスタンスが作成されるたびに、その時点で IS を提供する必要があります。これにより、依存関係グラフが複雑になります。さらに、DE が自身の状態の整合性を維持する責任がある場合、なぜ外部サービスに依存するのでしょうか? サービスが何らかの動作を呼び出す必要がある場合がありますが、整合性を維持することは、通常、外部サービスなしで実現できます。実際、このように外部サービスに依存することは、通常、責任が混同されていることの匂いです。

II、III) これには、不変条件の保護などが含まれます。たとえば、エンティティは、例外を発生させることによって、その値が一貫性のない状態にならないようにすることができます。これは OOP の基本的な前提であり、状態をカプセル化し、動作を公開します。

IV) エンティティに関連付けられた動作 (通常は状態の変更を伴います) も、エンティティに配置する必要があります。そのような動作でサービスを使用する必要がある場合は、そのサービスを渡しますが、通常はエンティティにできるだけ多くの動作を配置するようにします。これは常に完璧であるとは限りませんが、理想に向かって努力することはできます。

d) 確かに、IS を注入すると言うとき、DE から IS への必要なインスタンス参照を持つことを意味します。上記の理由により、これはお勧めできません。IS を DE ビヘイビア メソッドに渡す方が優れていますが、IS インターフェイスに目前のビヘイビアに関係のないものがたくさんある場合、SRP/ISP に違反する可能性があります。これは ISP の基本的な前提です。依存関係は、たまたま必要な機能を含む肥大化したインターフェイスとは対照的に、特定のインターフェイスに作成する必要があります。

于 2013-01-30T21:04:17.780 に答える
3

ドメイン エンティティは、永続性 (リポジトリ) やプロセス (ドメイン サービス) について何も認識しない必要があります。代わりに、アプリケーションはこれらをまとめて調整します。

たとえば、リポジトリのオーケストレーションは次のとおりです。

ISomeAggregateRepository repository = //TODO: Construct repository and load it with the de-hydrated aggregates you intend to work with under your scope.
foreach (SomeAggregate someAggregate in repository) //The repository functions like an in memory collection.
{
    someAggregate.DoSomethingCool(); //The domain aggregate would expose an event to let the repository know that this method has been called and that the instance should be saved afterwards. (mimicking saving to a reference)
}

たとえば、ドメイン サービスのオーケストレーションは次のとおりです。

ISomeDomainService service = new ConcreteInfrastructuralSpecificDomainService();
service.DoSomethingCool(SomeAggregate target); //Send the aggregate to the domain service, not the other way around.

私は長い間あなたと同じ道を歩んでいて、非常に混乱していましたが、私の例が示すようにコードを整理する方法を理解すると、物事はより明確になりました.

リポジトリ、ドメイン サービス、および場合によっては作業単位の実装 (通常はインフラストラクチャ固有) を選択するのはアプリケーションであるべきだということを覚えておいてください。

お役に立てれば!

アップデート

A - アプリケーション レイヤーのみがドメイン サービスを作成して使用する必要があり、ドメイン エンティティはその存在を認識してはならないということですか? しかし、なぜ?

頭のてっぺんから思いついたものをいくつか紹介します。これを完全なリストとは考えていませんが、私の声明を正当化するには十分なはずです。

  • カプセル化 (ドメイン集約の内部動作は、渡されるリポジトリおよび/またはドメイン サービスの実装に公開されません)

  • リポジトリ/ドメイン サービスは本質的にインフラストラクチャであるため、ビジネス ロジックをクリーンで表現力豊かに保つビジネス ドメインに結合するべきではありません。(インターフェースはドメイン内にあり、アプリケーションが必要以上のプロジェクトを参照する必要がないように、リポジトリ/ドメイン サービスを実装する契約上の方法を実装者に提供します。)

  • ドメインがリポジトリ/ドメイン サービスを認識しないようにすると、デカップリングと、間違った方向に進む可能性のある依存関係がさらに強化されます (インフラストラクチャ プロジェクトはドメイン プロジェクトを参照する必要があります。具体的な実装を参照)。

  • 変更管理/保守性 (オニオン アーキテクチャを参照)

B - あなたが投稿したコードはすべてアプリケーション層にあると思いますか?

あなたは正しい良い先生です!

于 2013-01-30T21:01:39.617 に答える