2011-12-21 7 views
3

私はリポジトリからDTOを取得するサービス層を持っています。そのDTOのプロパティによっては、DTOで計算を実行するために2つの戦略のうちの1つを使用する必要があります。適切な戦略を返すためのファクトリを作成しました。オブジェクトをインスタンス化するためにDIコンテナ(Munq)を使用しています。これはDependency Injectionの正しい使用ですか?

public class CalculationFactory 
{ 
    private readonly IDependencyResolver _resolver; 
    public CalculationFactory(IDependencyResolver resolver) 
    { 
     ThrowIfNullArgument(resolver, "resolver", typeof(IDependencyResolver)); 
     _resolver = resolver; 
    } 

    public static ICalculation CreateCalculator(int serviceType) 
    { 
     switch (serviceType) 
     { 
      case 1: return _resolver.Resolve<ICalculation>("Type1"); 
      case 2: return _resolver.Resolve<ICalculation>("Type2"); 
      default: return _resolver.Resolve<ICalculation>("InvalidType"); 
     } 
    } 
} 

使用するために適切な計算をインスタンス化/解決するために使用することができるように、私は工場をインスタンス化するとき、依存リゾルバに渡すために私を必要とします。これは正しいアプローチですか?新しいタイプの計算を追加したい場合は、工場のCreateCalculatorメソッドを更新して新しいタイプを登録する必要があります。

更新(ロング) 私は恐れている提案を実際に牽引していません。私は.NetのMark's DIのコピー、特にリファクタリングの第6章に戻ってきました。だから私はクラスMeterReadingsと私はランタイム値に基づいて2つの計算のいずれかを使用して電荷を計算する必要があります。私は抽象的な工場をミックスに追加しますが、私のコンクリート工場ではまだ新しいが必要です。私はここでのポイントを欠けているように感じる:

public enum ServiceType 
{ 
    Actuals = 1, CopyBlock, 
} 

public interface IChargeCalculator 
{ 
    decimal CalculateCharge(); 
} 

public interface IChargeCalculatorFactory 
{ 
    IChargeCalculator CreateChargeCalculator(ServiceType serviceType); 
} 

public class MeterReading 
{ 
    private readonly IChargeCalculatorFactory chargeCalculatorFactory; 
    public MeterReading(IChargeCalculatorFactory chargeCalculatorFactory) 
    { 
     if (chargeCalculatorFactory == null) 
      throw new ArgumentNullException("chargeCalculatorFactory"); 
     this.chargeCalculatorFactory = chargeCalculatorFactory;  
    } 
} 

public class ConcreteChargeCalculatorFactory : IChargeCalculatorFactory 
{ 
    public IChargeCalculator CreateChargeCalculator(ServiceType serviceType) 
    { 
     switch (serviceType) 
     { 
      case ServiceType.Actuals : return new ActualsChargeCalculator(); 
      default: return new CopyBlockChargeCalculator(); 
     } 
    } 
} 

しかし、私の容器に私は別の電卓を登録することができ、私は具体的な工場としてコンテナに渡した場合、私のような何かを得る(テストしていません)、次のどの率直に言って、私にとってかなり合理的だ。どんなフィードバック/明確化も歓迎されるでしょう。

Container.Register<IChargeCalculator>("Actuals", 
             c => new ActualsChargeCalculator()); 
Container.Register<IChargeCalculator>("CopyBlock", 
             c => new CopyBlockChargeCalculator()); 
... 
public enum ServiceType 
{ 
    Actuals = 1, CopyBlock, 
} 

public interface IChargeCalculator 
{ 
    decimal CalculateCharge(); 
} 

public class MeterReading 
{ 
    private readonly IDependencyResolver chargeCalculatorFactory; 
    private ServiceType serviceType; 
    public MeterReading(IDependencyResolver chargeCalculatorFactory) 
    { 
     if (chargeCalculatorFactory == null) 
      throw new ArgumentNullException("chargeCalculatorFactory"); 
     this.chargeCalculatorFactory = chargeCalculatorFactory;  
    } 

    public decimal Charge 
    { 
     get 
     { 
      return chargeCalculatorFactory.Resolve<IChargeCalculator>(serviceType.ToString()); 
     } 
    } 
} 
+4

ここで依存関係を解決する方法は、通常、「サービスロケータ」パターン(または、あなたの視点に応じてアンチパターン)と呼ばれます。http: /blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx私は通常、Service Locatorパターンを避けようとしますが、やむを得ないこともあります。 – CodingWithSpike

+0

rally25rsに感謝します。私はMarkの投稿を見ましたが、Service Locatorからより良いものにリファクタリングする方法はありません。 –

+3

ここにある方法:http://stackoverflow.com/questions/1943576/is-there-a-pattern-for-initializing-objects-created-via-a-di-container/1945023#1945023 –

答えて

3

はい、あなたは正しい方法でそれをやっていると言います。

「依存関係リゾルバを渡す」必要があると書いても、必要なクラスにファクトリクラスを注入できないのはなぜですか?それから依存関係リゾルバへのファクトリ依存関係は、依存リゾルバ自体(それ自身)によって解決されるべきです。

私はその文が意味をなさないことを願っています。

私は「クリーナー」ソリューションを考え出しましたが、まだ見つかっていません。質問に示唆されているもの(これはまったく同じではありません)と同様の解決策は確かに可能ですが、同じコードを別の場所に移動するだけであることが分かります。 Remoは、ファクトリメソッドの代わりにファクトリクラスで行うこともできると書いています。

これは、lampdaまたはヘルパークラスの作成を決定するのと同じです。それはほとんどreadabiltyになります。私にとっては、ファクトリメソッドは大きなものにすぎず、モジュールイニシャライザやブートストラップの継ぎ目で混乱することになります。

私はNinjectをお勧めします。本当にいいDIです。また、ドキュメントでは忍者の例を使用しています)

+1

私はNinject 。しかし、海賊には注意してください。 – Amy

+0

ファクトリクラスの注入の使用例を教えていただけますか?ファクトリを挿入する場合、オブジェクトグラフを破ることなく、つまり計算で他のオブジェクトを解決する必要がある場合、Createメソッドで計算を解決するにはどうすればよいですか。私はちょうど適切なオブジェクトを新しくすることはできません。それは理にかなっていますか? Ninjectのおかげで、私は今までMunqに満足しています。比較的軽くて速いです。 –

0

ここでは、あなたのバインディングに対してメタデータを使用し、実装ごとにバインディングを作成することをお勧めします。次に、バインディングを使用してメタデータを取得し、使用するバインディングを選択します(Ninject conditional binding based on property value)。おそらく、これはMunqで可能かもしれないし、そうでないかもしれませんか?わからない。

この質問に答えた人(レモ)は、人の建築家の一人であり、非常に知識があります。私は彼の答えは体重の多くを保持する必要がありますと信じています。 (私はninjectメーリングリストの購読者であり、彼がすべての質問の約半分に答えているのを見ている)。

関連する問題