IoCコンテナーを使用します。 長所と短所

Unity IoCコンテナーの最も重要な部分の1つであるエンタープライズライブラリーの新しいバージョンのリリースに照らして、コンテナーのIoC(制御の反転)トピックへの関心の高まりを個人的に期待しています。これは、本質的に、よく知られているサービスロケーターパターンの実装です。

このトピックでは、このようなコンテナの「適切な」使用方法について議論し、初心者に「どこでも」使用することを警告したいと思います。 まあ、「新しい技術」の可能性に興味のある人だけが好奇心should盛であるはずです。

問題の背景


通常、IoCコンテナの知識は、クラス設計原則(SOLID)に従う必要性、つまり、各クラスが特定のオブジェクトではなく抽象化(インターフェース)に依存するという最後の原則に従う必要性の認識によって促されます。これらすべての依存関係がコンストラクターで宣言されている場合。

つまり、次の形式のコード:
class TextManager {
public TextManager(ITextReader reader, ITextWriter writer) {
}
}


* This source code was highlighted with Source Code Highlighter .

これは良いことで、次の形式のコード:

class TextManager {
public TextManager(TextFromFileReader reader) {
}

public property DatabaseWriter Writer {
set {
_writer = value ;
}
}
}

* This source code was highlighted with Source Code Highlighter .

これは悪いです。

同時に、アプリケーション/ライブラリが大きい場合、ITextWriterは多くのクラスで使用され、使用するライタはライブラリの入り口で決定されます(たとえば、データベースにライターがあり、共通のインターフェイスを持つファイルがある場合)。 ITextWriterをDatabaseWriterに1か所で接続します。

SOLIDが登場する前は、静的クラスのライブラリ内でITextWriter型の変数を宣言し、現在使用されている特定のWriterをそこに格納するのが通常と考えられていました。 しかし、通常のアーキテクチャについて考え始めると... :)静的クラスの欠点は明らかになります-各クラスが依存するもの、動作する必要があるもの、そうでないものは完全に不透明であり、このクラスで「ストレッチ」するものを想像することさえ怖いです突然、別のプロジェクトまたは少なくとも別のライブラリに転送する必要があります。

IoCコンテナー


問題を解決するために何が提供されていますか? このソリューションは、IoCコンテナの形式で長い間発明されてきました。必要な情報を取得するとすぐに、特定のクラスにインターフェイスを「バインド」します。

var container = new UnityContainer();
container.RegisterInstance<ITextWriter>( new DatabaseWriter());


* This source code was highlighted with Source Code Highlighter .


オブジェクトを作成する便利な方法があります:
container.Resolve<TextManager>();
* This source code was highlighted with Source Code Highlighter .


そして、1つの依存関係の例でコンテナーの利点が明らかでない場合、デザイナーが2〜3個のインターフェイスを必要とし、そのようなクラスが少なくとも5〜10個あると想像すると、コンテナーの使用は多くの本当の救いのようです。

コンテナが良いとき..


実際、Unityは複雑な複合アプリケーションでアクティブに使用するために作成されており、多くの実装は同一のインターフェイスを備え、実装間の相互依存関係の非線形ロジックを備えています。 簡単に言えば、DbWriterとTextWriterの2つの実装を備えたIWriterインターフェイスが1つだけでなく、たとえばIReaderとITextProcessorもあり、それぞれに3〜4の実装があり、TextWriterがCsvReaderでのみ動作する場合、 ohmとExcelReader、およびどのリーダーを使用するかは、現在のTextProcessorの特定のタイプ、およびムーンフェイズに依存します。

具体的なコード例、Unityの使用を説明することは非常に困難です。Unityを使用すると、私の観点からは正当化され、大量の不要なコードでテキストが乱雑になりません。 しかし、説明されている「例」は、このような複雑で複雑なタスクの類似点を作成します:)

そしていつ-本当にない


container.Resolve()のような構造の適用 これは非常に便利なようで、最初はもっと頻繁に使用し、可能な限りこの方法でクラスをインスタンス化するのが魅力的です。 これはすべて、ライブラリ/アプリケーションの「深さ全体」にコンテナを転送し、クラスコンストラクターを介して、または過去に戻って静的クラスを介してIUnityContainerへのアクセスを整理することにつながります。
class TextManager {
public TextManager(IUnityContainer container) {
_writer = container.Resolve<IWriter>();
_reader = container.Resolve<IReader>();
}
}

* This source code was highlighted with Source Code Highlighter .


これはUnityContainerの極端な使用法です。 なぜなら:


...利益!


まとめると、IoCコンテナの使用は、特定の実装間の相互依存関係が複雑に絡み合っている状況で、ライブラリ/アプリケーションの最高レベルでのみ理想的であるように思えます。
つまり、ライブラリへのエントリポイントの直後に、Unityでインターフェイスの実装を登録し、できるだけ早く必要な型を解決する必要があります。 したがって、Unityのすべての力を使用して、複雑な依存オブジェクトの生成プロセスを簡素化し、同時に、優れたデザインの原則に従い、アプリケーションでの非常に抽象的な「コンテナー」の使用を最小限に抑え、テストを簡素化します。

PS私自身はこのトピックの第一人者とはほど遠いので、コメントでは、IoCコンテナーの他の可能なアプリケーションと同様に、自分の間違いについて聞いてうれしいです。

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


All Articles