2011-10-21 11 views
6

私は最近、DIを適切に行うことについて尋ねました。ブログに関する記事へのリンクがいくつかあります。私は今、より良い理解を持っていると思います。それは、オブジェクトをロジックから分離し、工場に入れることです。しかし、すべての例はウェブサイトのようなものであり、起動時にすべての配線を行うと言います。 newがすべての依存関係をすべて通過している大きな工場を呼び出します。実行時にファクトリをいつどこに呼び出すか?

しかし、前もってすべてをインスタンス化したくない場合はどうすればよいですか?私は委任できる他のオブジェクトのリストを含むオブジェクトを持っていますが、それらは高価であり、一度に1つずつ使用されるので、必要なときにそれらを構築し、完了したら収集させます。私はAのロジックの中にnew B()を入れたくないのですが、私はむしろDIを使いたいのですが、どうですか? Aは工場に電話できますか?工場が現在の依存関係を含む状態を維持していない限り、それははるかに良いとは思われません。私はちょうどBの完全なリストをAに渡すことは無駄であるので、それが構築されたときには望んでいません。あなたがしたい場合、それは(Aがゲームレベルで、Bは単一の画面で)論理的な意味になりますが、Bが作成されたときにどのような場合にAの論理が指示ものの、Bは必ずしもは、A内であることをを持っていません。

だから、誰が工場に電話してBになるのですか?

説明:私はDIのフレームワークを使用していません。私は、用語DIがそれを意味するのだろうか?

+0

グレート質問:

は今の代わりにExpensiveImplを注入するのは、他のインスタンスにServiceProxyを注入することができます。私もこの問題で混乱してきました。また、時々私は何か(とそれの任意の数)の複数のインスタンス化をしたいと思うし、それがうまくいく方法が非常に混乱しています。私はちょうどそれを吸い込み、 'IKernel'を注入しましたが、私はそれが怒られていることを理解するために与えられました。 (私の経験では、非常に強力で、それを後悔していません - そして、私はDIフレームワークを "交換する"ことに遠くから関心を持っていないので、利益は私には間違いです) –

+0

それは、パターンのいくつかの宗教的な理解を持っています。すべてのタイプがIKernelを知っているか、DIフレームワークのあなたの味の中で何が言われていようとも、私は行き過ぎではありませんが、時にはそれが最善の方法です。私もこれをやったし、何も私の上で爆発しなかった。 – Andy

答えて

6

Ninjectでは、Func<B>を登録し、そのコンストラクタでAを要求できます。

Bが既に登録されている場合、オートファックは自動的にFunc<B>を提供します。

また、より直接的なアプローチをとり、Bの明示的なファクトリを定義して、そのファクトリにコンストラクタを要求することもできます。そのちょっとしたタイピングは、遅れて初期化したいすべての依存関係のためのファクトリを作成する必要があります。フレームワークを使用して@Not How do I handle classes with static methods with Ninject?


:あなたができるならば、私はおそらく1を使用してに見てね:IoCの/


はここSOそれはNinjectスタイルのファクトリメソッドを示して答える別ですDIフレームワークは、通常、あなたのために遅延作成を処理します。

自分自身をロールバックしたい場合は、Bを作成するファクトリをAオブジェクトに渡します。また、生のFuncsを気に入らず、すべてのオブジェクトに対して明示的なファクトリを作成する必要がない場合は、Lazy<B>を使用してより正式なソリューションを探すことができます。

+1

+1、素晴らしい、賢明な答え。 – Andy

+0

うわー、素敵!アンディと同意する。 –

+0

私が行った解決策は、これらの回答のどれともまったく一致しませんでした(私はほとんどのことを前もってインスタンス化して行っていました)が、DIのアプローチについていくつかの新しい洞察を与えてくれました。 – Tesserex

1

作成に費用のかかる、ほとんど必要としないオブジェクトを使用するためのパターンは、通常2つあります。 David Faivreが示唆するように、最初のパターンは工場を使用しています。もう1つはプロキシを使用することです。

プロキシは設計上の観点からです。おそらく最もクリーンなソリューションですが、実装するにはさらにコードが必要な場合があります。これは、アプリケーションが完全にこれを認識できないため、余分なインターフェースを必要としないため(工場のアプローチの必要性など)、最もクリーンです。ここで

いくつかのインタフェースと高価な実装と簡単な例です:

interface IAmAService 
{ 
    void DoSomething(); 
} 

class ExpensiveImpl : IAmAService 
{ 
    private object x = [some expensive init]; 

    void IAmAService.DoSomething() { } 
} 

んが、あなたがその実装の作成を遅らせることができるインターフェイスに基づいて、プロキシ、実装することはできません。

class ServiceProxy : IAmAService 
{ 
    private readonly Func<IAmAService> factory; 
    private IAmAService instance; 

    public ServiceProxy(Func<IAmAService> factory) 
    { 
     this.factory = factory; 
    } 

    void IAmAService.DoSomething() 
    { 
     this.GetInstance().DoSomething(); 
    } 

    private IAmAService GetInstance() 
    { 
     // TODO: Implement double-checked lock only a single 
     // instance may exist per ServiceProxy. 
     if (this.instance == null) 
     { 
      this.instance = this.factory(); 
     } 

     return this.instance; 
    } 
} 

このプロキシクラスは、David Faivreが答えたとおりに、ファクトリーデリゲートを依存関係として受け入れますが、この方法ではアプリケーションはFunc<IAmAService>に依存する必要はなく、IAmAServiceに依存するだけです。

// Create the proxy 
IAmAService service = 
    new ServiceProxy(() => new ExpensiveImpl()); 

// Inject it into whatever you wish, such as: 
var customerService = new CustomerService(service); 
+1

+1 - 私はいつも "工場"を作るために、IService用とIServiceFactory用の2つのインターフェースを作成し、両方のインターフェースを作成しなければならないと私に尋ねました。(これがFunc - 私は怠け者だからおそらくそうするだろう)。しかし、私はあなたがIServiceの直接実装で工場を隠しているという事実が気に入っています。まだ2つの実装がありますが、少なくともその1つのインタフェースだけです。 Neeto。 –

関連する問題