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 오브젝트들의리스트를 생성한다. 그러나 나는 에 SomeObject과 관련된 내용을 하드 코딩하지 않기를 바랍니다. 런타임에 문제를 해결하기 위해 몇 가지 형태의 Dependency Injection이 필요합니다. 이것을 처리하는 가장 좋은 방법은 무엇입니까? 다음을 고려했습니다.

1. Data의 생성자에 SomeObject의 인스턴스를 전달합니다.이 방법을 사용하면 .GetType()으로 해당 유형을 가져올 수 있으며 Data.cs에 변수 System.Type에 저장하고 루프에 Activator.CreateInstance을 사용하여 목록에 추가 할 새 개체를 만들 수 있습니다. Data은 올바르게 이해하면 캐스팅 할 구체적으로 SomeObject 클래스에 대해 알아야합니다.

2. 내 IoC 컨테이너의 인스턴스를 Data의 생성자으로 전달하고 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

개체의 생성을 다른 것으로 위임 할 수 있습니다. 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; 
    } 
} 

그런 식으로 Data의 인스턴스를 생성하는 하나의 책임이

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

은 추상화에하지 concretions에만 의존한다. 그것들은 런타임에 컴포지션 루트에서 결정/구성 될 수 있습니다.

+1

이 답변은 대단하며 트릭을해야합니다! 대단히 감사합니다 = D – user1548103

관련 문제