実際、「正しい」方法は、他の選択肢がまったくない場合を除き、工場をまったく使用しないことです(単体テストや特定のモックのように-量産コードの場合は工場を使用しません)。そうすることは、実際にはアンチパターンであり、どんな場合でも避けるべきです。DIコンテナーの背後にある全体的なポイントは、ガジェットが作業を行えるようにすることです。
前の投稿で前述したように、IoCガジェットにアプリ内のさまざまな依存オブジェクトの作成を担当させる必要があります。つまり、DIガジェットにさまざまなインスタンス自体を作成および管理させます。これがDIの背後にある全体のポイントです。オブジェクトは、依存するオブジェクトを作成および/または管理する方法を決して知ってはいけません。そうしないと、疎結合が壊れます。
既存のアプリケーションをすべてのDIに変換することは大きなステップですが、そうする際の明らかな困難は別として、あなたのバインディングの大部分を自動的に実行するDIツールを探索することも必要になります。 (Ninjectのようなものの中核は、"kernel.Bind<someInterface>().To<someConcreteClass>()"
インターフェイス宣言をそれらのインターフェイスを実装するために使用したい具体的なクラスに一致させるために行う呼び出しです。DI ガジェットがコンストラクター呼び出しをインターセプトして提供できるようにする「バインド」呼び出しですいくつかのクラスの典型的なコンストラクター(ここに示す擬似コード)は次のとおりです。
public class SomeClass
{
private ISomeClassA _ClassA;
private ISomeOtherClassB _ClassB;
public SomeClass(ISomeClassA aInstanceOfA, ISomeOtherClassB aInstanceOfB)
{
if (aInstanceOfA == null)
throw new NullArgumentException();
if (aInstanceOfB == null)
throw new NullArgumentException();
_ClassA = aInstanceOfA;
_ClassB = aInstanceOfB;
}
public void DoSomething()
{
_ClassA.PerformSomeAction();
_ClassB.PerformSomeOtherActionUsingTheInstanceOfClassA(_ClassA);
}
}
そのコードのどこにも、SomeConcreteClassAまたはSomeOtherConcreteClassBのインスタンスを作成/管理/リリースするコードがなかったことに注意してください。実際のところ、どちらの具体的なクラスも参照されていません。それで...魔法はどこで起こったのですか?
アプリの起動部分では、次の処理が行われました(これも擬似コードですが、実際の(Ninject)にかなり近い...):
public void StartUp()
{
kernel.Bind<ISomeClassA>().To<SomeConcreteClassA>();
kernel.Bind<ISomeOtherClassB>().To<SomeOtherConcreteClassB>();
}
そこにある少しのコードは、Ninjectガジェットにコンストラクターを探し、それらをスキャンし、処理するように構成されたインターフェースのインスタンスを探して(「バインド」呼び出し)、どこでも具象クラスのインスタンスを作成して置換するように指示しますインスタンスが参照されます。
Ninjectを補完する優れたツールがあり、Ninject.Extensions.Conventions(別のNuGetパッケージ)と呼ばれ、この作業の大部分を実行します。これを自分で構築する際に経験する優れた学習体験から離れることはありませんが、自分で始めるには、これは調査するためのツールかもしれません。
メモリが機能する場合、Unity(以前はMicrosoftから現在はオープンソースプロジェクト)には、同じことを行うメソッド呼び出しが2つあり、他のツールには同様のヘルパーがあります。
DIトレーニングの大部分については、Mark Seemannの本を読んでくださいNinjectの本で、Ninject専用に書かれた別のリソースを紹介します。私はそれと良い読み物を持っています:Dependency InjectionのためのNinjectの習得