IoC を一般的な設定リポジトリとして使用しない理由はありますか?

StackOverflow https://stackoverflow.com/questions/115039

  •  02-07-2019
  •  | 
  •  

質問

仮に、 アプリケーションの設定 クラスは、TimeoutPeriod、DefaultUnitOfMeasure、HistoryWindowSize など、アプリケーションに適用される設定の一般的なリポジトリです。そして、MyClass がそれらの設定の 1 つである DefaultUnitOfMeasure を使用するとします。

制御コンテナの反転の適切な使用に関する私の解釈は、クラスの依存関係をそのコンストラクターで定義するというものです。これが間違っている場合は修正してください。

public class MyClass {
  public MyClass(IDataSource ds, UnitOfMeasure default_uom) {...}
} 

次に、次のようなものでクラスのインスタンスを呼び出します

var mc = IoC.Container.Resolve<MyClass>();

どこ Iデータソース には具体的な実装が割り当てられており、default_uom は ApplicationSettings.DefaultUnitOfMeasure 財産。しかし、私は、これらすべての輪を飛び越えるのに本当に必要があるのか​​どうか疑問に思っています。どのような問題に直面しているのでしょうか?

public class MyClass {
  public MyClass(IDataSource ds) {
    UnitOfMeasure duom = IoC.Container.Resolve<UnitOfMeasure>("default_uom");
  }
} 

はい、私のクラスの多くは最終的に次への依存関係になります。 IoC.コンテナ しかし、それは私のクラスのほとんどが持つ依存関係です。クラスが結合されている限り、それを最大限に活用する必要があるかもしれません。アジャイルの達人、どこが間違っているのか教えてください。

役に立ちましたか?

解決

IoC.Container.Resolve("default_uom");

これは、IoC コンテナーをサービス ロケーターとして使用する古典的なアンチパターンであると考えられます。結果として生じる主な問題は次のとおりです。

  • コンテナーの構成が間違っている場合でも、アプリケーションがフェイルファストで失敗することはなくなりました (アプリケーションがコード内で特定のサービスを初めて解決しようとしたときにのみわかります。これは、特定のロジック/状況のセットを除いて発生しない可能性があります)。
  • テストが難しくなります - もちろん不可能ではありませんが、テスト用にウィンザー コンテナーの実際の (そして半構成された) インスタンスを作成するか、IWindsorContainer のモックをシングルトンに注入する必要があります。これにより、テストに多くの手間がかかります。コンストラクター/プロパティを介してモック/スタブ サービスをテスト対象のクラスに直接渡すことができるだけと比較してください。
  • この種のアプリケーションの保守は困難です (構成が 1 か所に集中していない)
  • 他の多くのソフトウェア開発原則 (DRY、SOC など) に違反します。

元のステートメントの懸念すべき部分は、ほとんどのクラスが IoC シングルトンに依存関係を持つことを暗示しています。すべてのサービスがコンストラクター/依存関係を介して注入されている場合、IoC との密結合は例外となるはずです。ルール - 一般に、コンテナに依存するのは、何か難しいことをしているときだけです。循環依存関係の問題を回避したい場合、または何らかの理由で実行時にコンポーネントを作成したい場合でも、多くの場合、汎用 IServiceProvider インターフェイス以外のものへの依存関係を避けることができ、ホームベイク IoC でスワップできるようになります。元のプロジェクト以外の環境でコンポーネントを再利用する必要がある場合は、サービス ロケーターの実装を使用します。

他のヒント

通常、IoC コンテナーに応じてクラスはあまりありません。私は通常、他のクラスに注入するファサード オブジェクトで IoC 要素をラップしようとしますが、通常、IoC 注入のほとんどはアプリケーションの上位層でのみ行われます。

独自の方法で作業を行う場合、テスト用の IoC 構成を作成せずに MyClass をテストすることはできません。これにより、テストの保守が困難になります。

もう 1 つの問題は、ソフトウェアのパワーユーザーが IoC 構成ファイルを編集して構成を変更しようとすることです。これは避けたいものです。IoC 構成を通常の構成ファイルと IoC 固有のものに分割することができます。ただし、通常の .Net config 機能を使用して構成を読み取ることもできます。

はい、私のクラスの多くは IoC.Container への依存関係を持ちますが、それは私のクラスのほとんどが持つ依存関係です。

これが問題の核心だと思います。実際、ほとんどのクラスが IoC コンテナ自体に結合されている場合は、設計を再考する必要がある可能性があります。

一般に、アプリはブートストラップ中にコンテナ クラスを直接参照するのは 1 回だけにしてください。コンテナーへの最初のフックを作成した後は、オブジェクト グラフの残りの部分は完全にコンテナーによって管理され、それらのオブジェクトはすべて、IoC コンテナーによって作成されたという事実を認識しないはずです。

特定の例についてコメントするには:

public class MyClass {
    public MyClass(IDataSource ds) {
        UnitOfMeasure duom = IoC.Container.Resolve<UnitOfMeasure>("default_uom");
    }
}

これにより、クラスを再利用することが難しくなります。より具体的には、限定されている狭い使用パターンの外でクラスをインスタンス化することが困難になります。これが最もよく現れる場所の 1 つは、クラスをテストしようとするときです。UnitOfMeasure をコンストラクターに直接渡すことができれば、そのクラスのテストがはるかに簡単になります。

また、UOM インスタンスの名前 (「default_uom」) の選択は、クラスの使用状況に応じて値がオーバーライドされる可能性があることを意味します。その場合、そのようにコンストラクター内の値を「ハードコード」する必要はありません。

コンストラクター注入パターンの使用 ではない クラスを IoC に依存させると、クライアントに IoC を使用するかどうかのオプションが与えられます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top