質問

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

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

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

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

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


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

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

@フラワーズ:ふーむ。私はあなたの拳の解決策が好きです。これは、私が試した両方のソリューションで機能するものを組み合わせたものです。私はまだオブジェクトについて考えすぎていて、インターフェイスや責任について十分に考えていなかったように思います。専用のファクトリーを試しましたが、バックグラウンドでコンテナーを使用してオブジェクトを作成したいのですが、クリーンな方法でコンテナーをオブジェクトに DI する方法がわかりません。

役に立ちましたか?

解決

少なくとも私のアプリケーションにおける依存関係の挿入の主な利点は、コンテキストに依存しないコードを作成できることです。その観点から見ると、2 番目の解決策は、DI がもたらすメリットを本当に覆すものであるように思えます。「神オブジェクト」がそれを参照する各クラスに異なるインターフェイスを公開する場合、それはそれほど悪いことではないかもしれません。しかし、そこまでやるなら、なぜフープまで行かないのかわかりません。

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

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

他のヒント

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

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

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

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

これに関するニック・ブルームハルトのミニシリーズをチェックすることをお勧めします。

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

私は「専用ファクトリー」の明示性を高く評価しており、自分でも使用していますが、パブリック インターフェイス (小さな「i」) が新しいファクトリーや新しい GetX メソッドによって変化し続けるため、これは自分の設計ではコードの臭いのように感じます。実装ごとに。ジェレミー・ミラーの本を読んだ後 IoCコンテナの緊張緩和の時が来た, 、ジェネリックを疑い、コンテナ自体を注入するのが最善策だと思います。

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

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

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

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

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

幸運を。

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

汎用サービス ロケーターに静的な依存関係を持たせることは、意図とコンテキストを失うため、悪い考えです。IoC はインスタンスを構築するときに、全体像を把握しているため、プロファイルやコンテキストなどのさまざまな要素に基づいて正しい依存関係を提供できます。

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

CSLでは、混乱を招く可能性があるため、命名に苦労しました。技術的にはインターフェースが DI を行うためのものではなかったため、最終的に CSL を選択することにしました。

それは本当によくある問題です。ウィンザーが組み込まれています 型付き工場施設 前述の欠点がなく、ファクトリーを使用する利点が得られます。

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