Mark Siman 2による.Netでの依存性注入-コンストラクター注入、存続期間

アプリケーション層間の依存関係 | コンストラクター実装、ライフタイム| アプリケーション、インターセプト、デコレータの横断的な側面

弱い一貫性のための闘争を続けます。 前のメモでは、アプリケーションのレイヤー間の依存関係を調べました。小さなフォームに移りましょう。

集約、コンストラクター実装


システムのオブジェクト/クラスは、レイヤーのように、相互に作用します。 クラス間にも依存関係があります。

たとえば、リスト1では、MyServiceはMyDataContext(EF)を使用します-MyDataContext依存関係があります。

class MyService { public void DoSomething() { using(var dbCtx = new MyDataContext()) { //  dbCtx } } }  1.   MyService  MyDataContext 

上記のコードには欠点があります。

-「Dictator」アンチパターンが使用されます。MyService自体が、依存関係MyDataContextのライフタイムを作成および制御します。
-Dependency Inversion Principle(DIP)に違反している(SOLIDのない「サイエンスライクな」記事の場合):MyServiceはMyDataContextの特定の実装に依存しているため、インターフェース/抽象クラスを使用した方が良いでしょう。

依存関係反転の原理(DIP)

実際、「特定の実装ではなく、インターフェイスに従ってプログラムする」という要件の同義語です。
(本からの引用)

集計によるコードの改善-リスト2:

 class MyService { private readonly IRepository Repository; public MyService(IRepository repository){ if(repository == null) throw new ArgumentNullException(nameof(repository)); Repository = repository; } public void DoSomething() { //  Repository } }  2. . MyService          Repository 

リトリート:

集計と合成に関する優れた記事は 、セルゲイ・テプリャコフによって書かれました。 とりわけ、この記事では、スマートスキームの作成方法を説明します。 ネタバレとして:集約を記述する回路は?

構成および集計スキーム
図1.構成と集約のスキーム

リスト2に戻りましょう。これは依存関係の実装ですが、最良のオプションは「コンストラクターの実装」です。 接続性は低下しましたが、疑問が生じました:処分リポジトリを呼び出す方法は? リスト1はUsingを使用したことを覚えていますか?

依存関係の制御を転送するクラスは、抽象化の特定の実装を選択する能力以上のものを失います。 また、インスタンスを作成する瞬間と、このインスタンスが利用できなくなる瞬間の両方を制御する機能も失われます。
(本からの引用)

興味深いメモ:クラスに4つ以上の依存関係(4つ以上のコンストラクターパラメーター)がある場合-これはリファクタリングについて考える機会です。 オブジェクトが実行する機能が多すぎるようで、単一責任原則(SRP-再びSOLID)に違反しています。

中毒寿命


「処分リポジトリの呼び出し方法」という質問に答えると、マークは妥協することを提案します。 MyServiceは、リソースを解放する必要性など、IRepository実装の機能を認識しないでください。 すなわち IRepositoryのこの定義は望ましくありません:

 interface IRepository : IDisposable { void DeleteProduct(int id); } 

このようなインターフェースは、特定の実装に関する知識の一部を消費者(MyService)に明らかにするという事実に加えて、可能な実装に制限を課します-IDisposableを実装する必要があります(おそらく必要ありません)。

また、IRepositoryの実装では、実装に関するこの知識が許可されます-リスト3。

 class SqlRepository : IRepository { IDataContextFactory DbContextFactory; public SqlRepository(IDataContextFactory dbContextFactory) { if(dbContextFactory == null) throw new ArgumentNullException(nameof(dbContextFactory)); DbContextFactory = dbContextFactory; } public void DeleteProduct(int id); { using(var dbCtx = DbContextFactory.Create()) { //  dbCtx } } }  3.  IRepository      

追加(最も重要ではない):SqlRepositoryはDataConextの存続期間を管理しますが、作成はファクトリーに移動されました。

これはトレードオフです。はい、SqlRepositoryはDataContextの有効期間を制御しますが、残りのコードには影響しません。

良い解決策は上で説明されていますが、それを適用することは常に可能ではありません。 たとえば、トランザクション性が必要です。

 public void DoSomething(int productId) { this.Repository.DeleteProduct(productId); this.Repository.DeleteHistory(productId); }  4.          

履歴の削除に失敗した場合、製品の削除をキャンセルする必要があります(巧妙な方法で、これは作業単位パターンです)。 その場合、DeleteProductメソッドとDeleteHistoryメソッドでデータベースに個別にコミットすることはできません。 どうする? 答えを探す場所を知っています。

続く


vy望の的となる主要な方法、つまりコンストラクターの実装を使用して実装された集約を検討しました。 彼らはオブジェクトの寿命を管理するトピックに触れました。 またね

Source: https://habr.com/ru/post/J344380/


All Articles