2011-08-26 29 views
8

SOLIDの原則によれば、クラスは他のクラスに依存することはできません。依存関係を注入する必要があります。それは簡単です:依存関係の逆転。オブジェクト作成

class Foo 
{ 
    public Foo(IBar bar) 
    { 
     this.bar = bar; 
    } 

    private IBar bar; 
} 

interface IBar 
{ 
} 

class Bar: IBar 
{ 
} 

しかし、私は私のFooクラスはIBARの背後に正確な実装を知らない、バーのを作成できるようにしたい場合は? (

  1. 「サービスロケータ」を使用して、解決を呼び出すオブジェクトの種類を注入し、ジェネリック
  2. を用いた反射
  3. を使用して: は、私はここ4つの解決策を考えることができ、それらのすべては、欠点を持っているように見えます) 方法。
  4. 分離ファクトリクラスを作成し、Fooの中にそれを注入する:

class Foo 
{ 
    public void DoSmth(IBarCreator barCreator) 
    { 
     var newBar = barCreator.CreateBar(); 
    } 
} 

interface IBarCreator 
{ 
    IBar CreateBar(); 
} 

class BarCreator : IBarCreator 
{ 
    public IBar CreateBar() 
    { 
     return new Bar(); 
    } 
} 

最終場合は自然に感じますが、BarCreatorクラスがあまりにもlitleコードを持っています。 あなたはどのように考えていますか?どちらが最適ですか?

+1

オプション4が正しい答えです。http://stackoverflow.com/questions/1943576/is-there-a-pattern-for-initializing-objects-created-via-a-di-container/1945023#1945023 –

+1

しかし、なぜFooにIBarを作成させたいのですか? Leaky Abstractionsに注意してください。 –

答えて

0

「私は私のFooクラスがBarを作成できるようにしたい」と感じると、もう1つルールが「分離の懸念」です。だからクラス作成のタスクを別のものに委ね、Fooはそのタスクについて心配するべきではありません。

2

すべては、ご使用のシナリオとニーズに応じて異なります。
私はあなたが言及したように、最も使用されるアプローチは、factoryだと思います。
NinjectやSprint.Net、Castle WindsorなどのIoCフレームワークを使用している場合は、サービスロケータも実行可能な解決策です(hereを参照)。

3

私はこの場合にFunc<IBar>を「注入する」のが好きです。同様に:

class Foo 
{ 
    public Foo(Func<IBar> barCreator) 
    { 
     this.bar = barCreator(); 
    } 

    private IBar bar; 
} 

interface IBar 
{ 
} 
2

冗長なファクトリインターフェイスに問題がある場合、ここでは2つの方法があります。

それはジェネリックで再利用可能:

interface IFactory<T> 
{ 
T Create(); 
} 

class DefaultConstructorFactory<T> : IFactory<T>, where T: new() 
{ 
public T Create() { return new T();} 
} 

や工場として無名関数を使用します。

public void DoSomething(Func<IBar> barCreator) 
{ 
var newBar = barCreator(); 
//... 
} 
+0

これは実際には機能しませんか? 'DefaultConstructorFactory 'を 'IFactory 'として渡すことはできません。 – fearofawhackplanet

3

これは、工場がために作られたものです。

工場のコードが少なすぎると感じる場合は、インラインでインスタンスを作成するだけでどのような利点があるのか​​お尋ねください。利点が追加されたコードのコストを上回る場合は、それを心配しないでください。

サービスの場所を個人的に避けたいのですが、実際に使用する必要がある場合は、とにかく工場の後ろに隠すことになります。サービスの場所は簡単に乱用される傾向があり、コンテナがコードと一致するようにすることができます。

コンテナの中には、コンポーネントのインスタンスを作成するときにコンテナが使用するファクトリを指定できるものがあります。この場合、クラスはIBarに直接依存する可能性がありますが、コンテナは新しいインスタンスが必要なときにIBarCreatorを呼び出します。キャッスルウィンザーは、例えば、APIにUseFactoryUseFactoryMethodというメソッドを持っています。

関連する問題