1

私は日々の開発にDependency InjectionとInversion of Controlを適用したいと思います。オブジェクトタイプがSomeObject(インターフェイスISomeObjectを実装しています)とします。私はIDataインターフェイスを実装するDataというこのオブジェクトを消費するクラスを持っています。Inversion of Controlのパラダイムを使用してカスタムオブジェクトのリストを作成

public interface ISomeObject { 
    int ID; 
    string Name; 
    bool IsAwesome; 

    void DoSomeStuffIfAwesome(); 
} 

public Class SomeObject : ISomeObject { 
    int ID; 
    string Name; 
    bool IsAwesome; 

    void DoSomeStuffIfAwesome() { /*stuff happens here*/ }   
} 

public interface IData { 
    List<ISomeObject> GetSomeObjects(); 
} 

public Class Data : IData { 
    List<ISomeObject> GetSomeObjects() 
    { 
     List<ISomeObject> objects = new List<ISomeObject>; // ??? Maybe and cast later? 

     //do some SQL stuff and get a SqlDataReader object called reader 
     while(reader.Read()) { 
      //ISomeObject someObj = ??? 
      //Read into the someObj.ID, someObj.Name and someObj.IsAwesome fields 
      objects.add(someObj); 
     } 
     return objects; 
    } 
}  

GetSomeObjects()方法はISomeObjectオブジェクトのリストを生成します。しかし、Data.csにはSomeObjectに関連するものをハードコードしたくありません。私は実行時に問題を解決するために何らかの形のDependency Injectionが必要です。これを処理する最善の方法は何ですか?私は以下を考慮しました:

1. DataのコンストラクタにSomeObjectのインスタンスを渡します。この方法で私は.GetType()の型を得ることができます。それをData.csの変数System.Typeに格納し、ループにActivator.CreateInstanceを使用してリストに追加する新しいオブジェクトを作成します。 Dataは、正しく理解すれば、特にキャストするSomeObjectクラスについて知る必要があります。

2.

Dataのコンストラクタに私のIoCコンテナのインスタンスを渡すだけ container.Resolve<ISomeObject>()を使用してオブジェクトの種類を解決します。これは私のIoCコンテナを利用することなくユニットテストの GetSomeObjects()メソッドを難しくするでしょう。私は単体テスト時にIoCコンテナを利用すべきではなく、必要なものを手作業でメソッドに渡すべきだと読んだことがあります。

3.パスとしてインスタンス化されてきたISomeObjectオブジェクトSomeObject - 私はそのようなSomeObject.GenerateList(IDataReader reader)などの方法で構築されたいくつかの、経由してオブジェクトを作成することを使用します。

+0

ある時点で、クラスは具体的でなければなりません。なぜ、** IData'の**実装で、特定の 'ISomeObject'オブジェクトのセットを返すことができないのですか? –

+0

それは非常によく状況になる可能性があります。私の理解はIoCとDependency Injectionの目標でした。コンシューマにコンセプトを教えてもらうことだけでしたので、コンシューマクラスをすばやく交換する必要はありません。ですから、将来SomeObjectをISomeObjectを実装する別のクラスに置き換えたい場合は、Data.cに触れることなくそれを行うことができます。 私は抽象化のアイデアが深すぎて、少し元気づける必要があります。おそらく私はData.csでSomeObjectをインスタンス化する必要があります – user1548103

+1

リーダーを取り、 'ISomeObject'を返すファクトリ(' ISomeObjectFactory')を使用してください。データをファクトリに挿入すると、ファクトリは 'ISomeObject'の構築方法を知ります。 – Nkosi

答えて

2

オブジェクトの作成を他のものに委譲できます。

Dataが結石に抽象化していないにのみ依存した方法 ISomeObject

using System.Collections.Generic; 
using System.Data; 

public interface IDbConnectionFactory { 
    ///<summary> 
    /// Creates a connection based on the given database name or connection string. 
    ///</summary> 
    IDbConnection CreateConnection(string nameOrConnectionString); 
} 

public class Data : IData { 
    private IDbConnectionFactory dbConnectionFactory; 
    ISomeObjectFactory someObjectFactory; 
    private string CONNECTION_STRING = "Connection string here"; 

    public Data(IDbConnectionFactory dbConnectionFactory, ISomeObjectFactory objectFactory) { 
     this.dbConnectionFactory = dbConnectionFactory; 
     this.someObjectFactory = objectFactory; 
    } 

    public List<ISomeObject> GetSomeObjects() { 
     var objects = new List<ISomeObject>(); 
     //do some SQL stuff and return a data reader 
     using (var connnection = dbConnectionFactory.CreateConnection(CONNECTION_STRING)) { 
      using (var command = connnection.CreateCommand()) { 
       //configure command to be executed. 
       command.CommandText = "SELECT * FROM SOMEOBJECT_TABLE"; 
       connnection.Open(); 
       using (var reader = command.ExecuteReader()) { 
        while (reader.Read()) { 
         //...Logic to populate item 
         var someObject = someObjectFactory.Create(reader); 
         if (someObject != null) 
          objects.Add(someObject); 
        } 
       } 
      } 
     } 

     return objects; 
    } 
} 

のインスタンスを作成するための単一責任を持って

public interface ISomeObjectFactory { 
    ISomeObject Create(IDataReader reader); 
} 

。それらは実行時にコンポジションルートで決定/設定できます。

+1

この回答は素晴らしいですし、トリックを行う必要があります!ありがとう= D – user1548103

関連する問題