2009-10-26 6 views
4

엄격하게 분리 된 인터페이스가 필요한 모듈에서 작업하고 있습니다. 특히 루트 객체 (데이터 소스)를 인스턴스화 한 후에는 사용자가 인터페이스를 통해 객체 모델과 상호 작용하기로되어 있습니다. 나는이 팩토리를 호출하는 실제 팩토리 객체를 가지고 있는데,이 인터페이스를 구현하는 인스턴스를 제공하기 위해 공급자를 호출한다. 이를 위해, 나는 데이터 소스에 몇 가지 방법을 제공했습니다 : 나는 (단순화하기 위해 즉석에서 몇 가지 세부 사항을 수정 한좋은 팩토리 메소드 구현입니까?

public class MyDataSource 
{ 
    private Dictionary<Type, Type> providerInterfaceMapping = new Dictionary<Type, Type>() 
    { 
     { typeof(IFooProvider), typeof(FooProvider) }, 
     { typeof(IBarProvider), typeof(BarProvider) }, 
     // And so forth 
    }; 

    public TProviderInterface GetProvider<TProviderInterface>() 
    { 
     try 
     { 
      Type impl = providerInterfaceMapping[typeof(TProviderInterface)]; 
      var inst = Activator.CreateInstance(impl); 

      return (TProviderInterface)inst; 
     } 
     catch(KeyNotFoundException ex) 
     { 
      throw new NotSupportedException("The requested interface could not be provided.", ex); 
     } 
    } 
} 

를 예를 들어, 구현 인스턴스에 전달 된 매개 변수를 포함하지 않는이 코드 그것은 만들어졌습니다). 이것은 C#에서 팩토리 메소드를 구현하기위한 좋은 일반적인 접근 방법입니까?

답변

4

오히려 한발 물러서서 공장 방법을 사용하는 것이 좋습니다. 제 의견으로는 그렇지 않습니다.

이 팩토리 메소드 더 이상 문제이며, 당신의 예를 몇 가지 보여

  • 당신은 구현에 하드 참조를 가질 필요는 (FooProvider는 IFooProvider에 추가), 정확히 상황 당신이다 처음에는 피하려고합니다. 나머지 코드가 IFooProvider 만 사용하더라도 라이브러리는 여전히 FooProvider와 밀접하게 결합되어 있습니다. FooProvider를 사용하는 다른 개발자는 공장 방법을 알지 못하는 경우 FooProvider를 직접 사용할 수 있습니다.
  • Activator.CreateInstance를 사용하고 있으므로 기본 생성자가있는 구현 만 지원합니다. 따라서 중첩 된 종속성을 사용할 수 없습니다.

종속성을 수동으로 제어하는 ​​대신 DI (Dependency Injection)를 살펴 보는 것이 좋습니다. 코드에 IFooProvider가 필요할 때마다 Constructor Injection을 제공하십시오.

+0

첫 번째 요지를 잘 모르겠습니다. 클라이언트는 FooProvider에 액세스 할 수 없으며 IFooProvider에만 액세스 할 수 있습니다. FooProvider는 어셈블리 내부에 있습니다. 아니면 너의 의미를 놓치니? –

+0

Re : 두 번째 요점은 매개 변수를 사용하는 구현을 실제로 지원합니다. 질문에서 언급했듯이 샘플을 단순화하기 위해 생략했습니다. 그것은 약간 어색하지만 공급자는 모두 데이터 소스를 유일한 매개 변수로 사용하여 필요한 모든 것을 얻을 것으로 기대됩니다. 이를 통해 .ctor parm을 통해 제공 될 수있는 FakeDataSource를 만들 수 있으므로 공급자 구현은 유닛 테스트 중에 가짜에 의존 할 수 있습니다. 가짜 데이터 소스는 가짜 공급자 만 제공합니다. –

+0

잘못된 가정을하면 유감스럽게 생각합니다. 즉, 내 비판의 일부가 귀하의 특정 상황에 적용되지 않는다는 것을 의미합니다. 그러나 나는 여전히 바퀴를 다시 만들 이유가 없다는 일반적인 조언을지지합니다. DI 컨테이너는 무료로이 작업을 수행 할 수 있습니다. –

1

기술적으로는 괜찮습니다. 그러나 대부분 공장에서는 동일한 유형의 인터페이스를 반환합니다 (예 : IFooProvider 또는 IBarProvider이 아닌 IProvider). 나에게 의미가 없습니다. FooProvider 및 BarProvider를 사용하려는 경우 다른 인터페이스가 필요한 이유는 무엇입니까? 하나의 인터페이스를 사용하고 FooProviderBarProvider을 구현했습니다.

+0

당신은 공정한 포인트를 만들고, 사실 'IFooProvider'와'IBarProvider'는 공통 비트를 위해'IProvider <>'로부터 상속받습니다. 'Foos','Bars','Bazs'는 모두 생성시 다른 매개 변수를 사용하기 때문에 Create 메서드의 서명이 다릅니다. –

0

팩토리 메서드를 사용하는 것이 올바른지 또는 잘못 되었든간에 (사용자가 묻는 것과 다르지 않습니다!), 구현은 나에게 잘 들립니다.

타입 매핑을 하드 코딩하는 것보다 더 잘 할 수있는 일은 구성 파일에 정보를 저장하고 앱에로드하는 것입니다.

3

dependency injection 당신 자신의 구현을 재발견하지 마십시오,Spring.NET 같은 기존 라이브러리 또는 Microsoft Unity 응용 프로그램 블록을 사용합니다.

종속성 삽입은 일반적인 프로그래밍 문제로 직접 해결할 필요가 없습니다. 거기에 몇 가지 멋진 가벼운 라이브러리가 있습니다 (나는 위에서 언급 한) 작업을 잘 수행합니다. 종속성을 정의하는 선언적 모델과 필수 모델을 모두 지원하며 자신이하는 일에 능숙합니다.

+0

나는 좋아하지 않을 것이지만 (어리석은) 정치적 이유 때문에, 내 기업 환경에서 어떤 종류의 인식 된 외부 의존성이 자동으로 즉각적으로 상실됩니다. ORM에 대해서도 마찬가지입니다 (이것은 내가 사용하고 싶은 것입니다). Boost를 사용할 수도 없습니다. –

+0

네, 그것은 매우 파괴적인 NIH의 사례입니다. 그리고 네, 그것은 조직을 죽이는 데 자기 파괴적입니다. 해산되기 전에 이것이 마지막 임무입니다. 나는 지난 5 년 동안 좋은 싸움을하려고 노력했지만, 나는 판매 나 정치력이 좋지 않습니다. 그리고 제가 제 동료 중 60-70 %와 함께 해고 당했고, 모든 개발 작업이 해외로 배송되기 시작했습니다. 풍차에서 기울어지는 것을 멈출 때입니다. –

+0

예, 불행한 상황입니다. 나는 당신이 다음 순위에서 좀 더 계몽적인 조직의 일원이되기를 바랍니다. – LBushkin

0

필자는이 패턴을 항상 사용하고 이러한 종류의 논리를 재사용 가능한 어셈블리로 추상화했습니다. 리플렉션, 제네릭 및 속성을 사용하여 런타임시 구체 유형을 찾아 바인딩합니다.http://www.codeproject.com/KB/architecture/RuntimeTypeLoader.aspx

구현 유형이 하드 코드되지 않으며 구현 유형이 프로젝트 어셈블리 참조가 아닌 설치에 의해 결정되므로 Mark의 우려 사항을 해결하는 데 도움이됩니다.

관련 문제