27

私が取り組んでいるペットプロジェクトにキャッスルウィンザーを使用しています。新しいオブジェクトを作成するには、コード内のさまざまな場所で IoC コンテナーを呼び出す必要があることに気付き始めています。このコンテナーへの依存関係により、コードの保守が難しくなります。

この問題を解決するために私が使用した2つの解決策があります

オブジェクトを作成する必要があるアプリケーションの部分に挿入できるコンテナのラッパーとして抽象ファクトリを作成しようとしました。これは機能しますが、キャッスルが独自のコンテナーを依存関係として注入するのに苦労するため、いくつかの欠点があります。そのため、手動で行う必要があります。この種のことは、IoC コンテナーの目的全体を無効にします。

メインの applicationcontroller クラスを使用して IoC コンテナーをラップし、中央のファクトリー/リポジトリーとして機能させました。これは非常に成功しましたが、このクラスは大きくなりすぎて、中心的な神のオブジェクトのように振る舞い、他のほとんどすべてのオブジェクトがそれを参照しています。

どちらのソリューションも機能しますが、どちらにも欠点があります。他の人が同じ問題を抱えていて、より良い解決策を見つけているかどうか、私は興味があります.


編集 問題は、オブジェクト B に依存するオブジェクト A ではありません。ここでは、通常、コンストラクター注入を使用するだけで、すべてが機能します。時々、タイプ A のオブジェクトが、存続期間中に可変数のタイプ B の他のオブジェクトを作成する必要がある場合があります。これを行う方法がわかりません。

@ブレア・コンラッド: メンテナンスの問題は今のところ深刻ではありません。いくつかのクラスは、container.Resolve<> を呼び出すコンテナー オブジェクトに依存していました。また、インフラストラクチャと思われるものに応じてコードを作成したくありません。私はまだ試している途中なので、このプロジェクトで ninject から城に切り替えるときに、多くのコードを変更する必要があることに気付きました。

@花:うーん。私はあなたの拳のソリューションが好きです。私が試した両方のソリューションから機能するものを組み合わせています。私はまだオブジェクトについて考えすぎていて、インターフェイス/責任について十分に考えていなかったと思います。専用の工場を試してみましたが、コンテナを舞台裏で使用してオブジェクトを作成したいと思いますが、コンテナをきれいな方法でオブジェクトにDIする方法がわかりませんでした。

4

7 に答える 7

12

IoC.Container.Resolve や ContainerFactory.GetContainer などの静的クラスは絶対に使用しないでください。

これにより、コードがより複雑になり、保守、再利用、および読み取りのテストが難しくなります。

通常、単一のコンポーネントまたはサービスには単一の注入ポイントしかありません。それがコンストラクターです (オプションのプロパティを使用)。また、一般的に、コンポーネントやサービス クラスは、コンテナーなどの存在を認識してはなりません。

コンポーネントの内部で動的な解決が本当に必要な場合 (つまり、名前に基づいて例外処理ポリシーまたはワークフローを解決する)、非常に具体的なプロバイダーを介して IoC 権限を貸与することを検討することをお勧めします。

于 2008-09-30T09:22:12.357 に答える
11

これについては、Nick Blumhardt のミニ シリーズをチェックすることをお勧めします。

http://blogs.msdn.com/nblumhardt/archive/2008/12/27/container-managed-application-design-prelude-where-does-the-container-belong.aspx

于 2009-02-01T08:16:24.290 に答える
4

少なくとも私のアプリケーションでは、依存性注入の主な利点は、コンテキストに依存しないコードを記述できることです。その観点からすると、2番目のソリューションは、DIがもたらす可能性のあるメリットを実際に覆しているように見えます。「神オブジェクト」がそれを参照する各クラスに異なるインターフェースを公開する場合、それはそれほど悪ではないかもしれません。しかし、あなたがそこまで行ったのなら、なぜあなたがそれをフープまで持って行かないのか分かりません。

例:GodオブジェクトにはgetFoo()メソッドとgetBar()メソッドがあります。オブジェクトAにはFooが必要であり、オブジェクトBにはBarが必要です。Aが1つのFooを必要とする場合、FooはAに直接注入されるべきであり、Aは神をまったく認識してはなりません。しかし、AがFoosを作成し続ける必要がある場合、Aに神への言及を与えることはかなり避けられません。しかし、神への言及の種類を狭めることによって、神を回すことによってもたらされる損害から身を守ることができます。神にFooFactoryを実装させ、Aに神によって実装されたFooFactoryへの参照を与える場合でも、コンテキストに依存しない方法でAでコードを記述できます。これにより、コードの再利用の機会が向上し、神への変更が予期しない副作用を引き起こさないという自信が高まります。たとえば、神からgetBar()を削除するときに、クラスAが壊れないことを確信できます。

しかし...とにかくこれらすべてのインターフェイスを使用する場合は、コンテナをラップするよりも、専用のファクトリクラスを作成し、ファクトリを含むすべてのオブジェクトをコンテナ内にワイヤリングする方がよいでしょう。コンテナは引き続きファクトリを構成できます。

于 2008-09-20T23:11:02.367 に答える
2

「目的に合わせて構築されたファクトリ」の明示性を高く評価し、自分で使用することもありますが、パブリック インターフェイス (小さな「i」) が新しいファクトリおよび/または新しい GetX メソッドで変化し続けるため、これは自分の設計のコードの匂いのように感じます。実装ごとに。Jeremy Miller のIt's time for IoC Container Detente を読んだ後、ジェネリックを疑っており、コンテナー自体を注入することが最善の方法です。

Jeremy の記事で提案されているような、ある種の IServiceLocator インターフェイスで Ninject、StructureMap、または Windsor をラップします。次に、最初に提案したようにループであっても、コード内のどこにでも IServiceLocator を返すだけのコンテナー ファクトリを作成します。

IServiceLocator container = ContainerFactory.GetContainer(); 
while( keepLooping )
{
    IExample example = container.GetInstance<IExample>();
    keepLooping = example.DoWork();
}

コンテナー ファクトリは常に同じインスタンスを返すことができ、IoC フレームワークを交換することもできます。

于 2008-09-23T13:50:40.067 に答える
1

@flipdoubtのフォローアップとして

サービス ロケータ タイプ パターンを使用することになった場合は、http://www.codeplex.com/CommonServiceLocatorを確認してください。役立つかもしれないいくつかの一般的な IoC フレームワーク (windsor、structuremap) で使用できるバインディングがいくつかあります。

幸運を。

于 2008-10-12T07:07:58.837 に答える
1

この場合、注入されると述べたように、強く型付けされたファクトリを使用することをお勧めします。これらのファクトリはコンテナーをラップできますが、追加のコンテキストを渡すことができ、追加の処理を行うことができます。たとえば、OrderFactory の Create は、コンテキスト パラメーターを受け入れることができます。

ジェネリック サービス ロケーターに静的な依存関係を持つことは、意図とコンテキストが失われるため、悪い考えです。IoC がインスタンスを構築するとき、全体像を把握しているため、プロファイル、コンテキストなどの多くの要因に基づいて正しい依存関係を提供できます。

CommonServiceLocator はこの目的のためのものではありませんが、使用したくなるかもしれません。CommonServiceLocator の主な目的は、クロス IoC コンテナーに準拠したいアプリ/フレームワーク用です。ただし、使用するアプリは、ロケーターを最適に 1 回だけ呼び出して、コンポーネントとその依存関係の階層を構築する必要があります。二度と直接呼び出すべきではありません。それを強制する何らかの方法があれば、そうするでしょう。プリズム内 ( http://www.microsoft.com/compositewpf) モジュールを構築するための IContainerFacade を導入しました。これはサービス ロケータですが、低レベルのものです。振り返ってみると、おそらく ModuleFactory か何かを作成し、IContianerFacade を使用してそれを取得し、それを使用してモジュールを解決し、Facade に直接アクセスする必要がありました。後知恵は 20/20 です。十分に低いレベルですが、実際には影響はありません。

CSLでは、混乱を招きかねないのでネーミングに苦労しました。最終的に CSL を選択したのは、技術的にインターフェイスが DI を行うためのものではなかったためです。

于 2008-10-22T18:09:03.817 に答える
0

それは本当によくある問題です。Windsor のビルトインTyped Factory Facilityは、前述の欠点なしに、ファクトリを使用する利点を提供します。

于 2011-04-23T00:56:58.197 に答える