2016-11-28 2 views
3

의존성 주입 + mvc에 대한 몇 가지 테스트를하고 있는데 질문이 있습니다.의존성 주입 - 인터페이스에서 객체 만들기

서비스 내에서 메소드의 결과가 될 객체 (트로프 인터페이스)를 어떻게 만들 수 있습니까?

추상 팩토리가이 문제를 해결할 수 있다는 것을 알았지 만 일부 사람들은 이것이 반 패턴이고 서비스 탐지기라고 말합니다.

public class ObjectFactory : IFactory 
{ 
    readonly Container container; 

    public ObjectFactory(Container container) 
    { 
     this.container = container; 

    } 

    public T Create<T>() 
     where T : class 
    { 
     return (T)this.container.GetInstance<T>(); 
    } 
} 

가 나는 이렇게 사용 :

내가 이런 짓을 한

public class CacheService : ICacheService 
{ 
    readonly IFactory factory; 

    public CacheService(IFactory factory) 
    { 
     this.factory = factory; 
    } 

    private void Insert(string name, object value) 
    { 
     if (this.CacheAvailable()) 
     { 
      Remove(name); 

      // This line where I ask for the container to resolve this interface 
      ICacheItemWrapper item = factory.Create<ICacheItemWrapper>(); 
      item.Value = value; 

      HttpRuntime.Cache.Insert(name, item, null, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration); 
     } 
    } 

    /* HIDDEN CODE */ 
} 

이 안티 패턴 아직인가?

변경해야 할 사항은 무엇입니까?

그것은 다음과 같이 그것을 할 잘못된 느낌

...

+2

'CacheService' 생성자가 단순히'IFactory' 대신에'ICacheItemWrapper'의 인스턴스를 요구할 수 있습니까? 그것은 의존성이 무엇인지를 생성자에게 광고함으로써 "반 패턴"문제를 해결할 것입니다. 이 문제에 대해 일반적으로 다른 사상 학교가 있습니다. 개인적으로 DI는 시간이 지남에 따라 레거시 코드베이스로 리팩토링 할 때 엄청나게 유용하지만 새로운 코드베이스를 만들 때 특정 종속성을 직접 제공하는 것을 선호합니다. – David

+0

하지만 같은 방법으로 다른 방법을 사용해야 할 때 각 방법마다 그 종류의 깨끗한 물체가 필요합니까? –

+0

흥미 롭습니다. 종속성 유형에 특정한 팩토리가 그 자체가 의미있는 의존성이 될지 궁금합니다. 그것은 내부 종속성을 감쌀 것이지만, 그 자체로 "깨끗한 인스턴스"를 제공 할 책임이 있습니다. (인스턴스 자체가 그 기능을 제공 할 수 없다고 가정하고, 그것이 불가능한 이유를 생각할 수는 없다. 왜냐하면 그것이 엣지 케이스가 존재하지 않는다는 것을 의미하지는 않는다.) 하나의 "서비스 로케이터 (locator) "와 유사한 기능을 수행합니다. 그러나 그것은 의존성 자체와 더 밀접하게 관련되어 있으며 그 의존성의 일부입니다. 정말로 큰 소리로 생각하고있어. – David

답변

1

솔루션은 예상보다 훨씬 간단합니다.

주입 할 팩토리가 요청할 수있는 유형 수에 제약이없는 Create<T>() 메소드를 포함하므로이 패턴은 서비스 탐지기 방지 패턴의 구현입니다.

또한 CacheService 구성 요소에 실제로 필요한 유일한 서비스는 ICacheItemWrapper입니다. IFactory은 복잡성을 증가시키고 테스트를 복잡하게하는 간접 지정의 추가 계층 만 추가합니다.

대신 직접 CacheService의 생성자에 ICacheItemWrapper를 삽입한다 : 당신의 CacheServiceICacheItemWrapper보다 오래해야하는 경우에이 obvously 문제를 야기 할 것이기 때문에

public CacheService(ICacheItemWrapper wrapper) { ... } 

당신이 대답은 너무 단순하다 생각할 수 있습니다. 예를 들어, 이 Singleton으로 등록되어 있고 ICacheItemWrapperScoped 인 경우 CacheServiceICacheItemWrapper을 삽입하면 Captive Dependency이됩니다.

이 경우 ICacheItemWrapper 종속성을 Func<ICacheItemWrapper>으로 변경하려고 시도 할 수 있지만 이로 인해 응용 프로그램 전체에서 변경 사항이 광범위하게 발생할 수 있습니다. 게다가, Func<T> 종속성은 이제는 그 종속성의 소비자가 그 종속성의 '휘발성'에 대한 지식을 가지고 있기 때문에 새는 추상화입니다. 이것은 소비자에게 아무런 관심도 없어야합니다. Func<T>을 삽입하면 소비자와 테스트가 복잡 해져서 이제 추상화를 처리하는 대신 추상화를 반환하는 대리인을 처리해야합니다.

캡 티브 종속성의 경우 솔루션은 수명이 짧은 구성 요소를 의존성에 따라 작성하는 프록시 클래스로 래핑하는 것입니다. 이 방법으로 소비자는 이러한 변화에 영향을받지 않습니다. 예 :

public class CacheItemWrapperProxy : ICacheItemWrapper 
{ 
    private readonly Func<ICacheItemWrapper> wrapperProvider; 
    public CacheItemWrapperProxy(Func<ICacheItemWrapper> wrapperProvider) { 
     this.wrapperProvider = wrapperProvider; 
    } 

    // ICacheItemWrapper method(s) 
    public object GetItem(string key) => this.wrapperProvider().GetItem(key); 
} 

CacheItemWrapperProxyICacheItemWrapper을 구현하고이를 통해 변경할 필요없이 소비자, 그 소비자에 주입 될 수있다. CacheItemWrapperProxy 자체는 Func<T>에 종속되지만이 Func<T> 격리와 CacheItemWrapperProxy의 사용은 응용 프로그램의 Composition Root 안에 위치 할 수 있습니다. 다시 말하지만 나머지 응용 프로그램은 영향을받지 않습니다.

container.Register<ICacheItemWrapper, CacheItemWrapperImpl>(Lifestyle.Scoped); 
container.RegisterDecorator<ICacheItemWrapper, CacheItemWrapperProxy>(Lifestyle.Singleton); 
container.Register<ICacheService, CacheService>(Lifestyle.Singleton); 

그 간단한 인젝터는 Func<T> 의존성 주입에 대한 아웃 - 오브 - 박스 지원하지 않는다주의 마십시오

이것은 당신이 간단한 인젝터이 등록하는 방법입니다. 위의 설명대로 응용 프로그램 구성 요소가 Func<T>에 종속되어서는 안되기 때문에 이는 신중한 것입니다. 이 규칙의 예외는 Simple Injector의 데코레이터 등록 기능입니다. RegisterDecorator 메서드는 Func<T> 종속성을 처리하기위한 기본 지원을 가지며, 유일한 경우이 T이 장식 된 유형 (사용자의 경우 ICacheItemWrapper)입니다.

간단히 말해 생성자 주입을 항상 사용하고 응용 프로그램 구성 요소에 Func<T> 종속성을 주입하지 마십시오.

+0

동일한 동작이 필요한 몇 가지 뷰 모델을 가지고 있기 때문에 약간 압도적인데, 그렇지 않습니다. 나는 이것이 너무 빨리 자라날 까봐 두렵다. 아니면 내가 틀렸어? –

+0

@LeandroSoares 질문을 업데이트하고 코드를 보여주십시오. 구체적인 예없이 유용하게 말할 수는 없습니다. – Steven

+0

한 번해볼 게요. 고맙습니다. –

1

예; 서비스 로케이터를 패턴으로 감싸고 있지만 여전히 반 패턴입니다.

대신 생성자가 Func<ICacheItemWrapper>을 받아 들여야합니다. 대부분의 IoC 컨테이너가 이것을 지원합니다.

이렇게하면 개발자가 정확한 요구 사항을 나열하고 IoC 없이도 직접 클래스 인스턴스를 만들 수 있습니다.

+0

필자는 이것을 보았습니다. 그러나 서비스에서 100 개의 뷰 모델을 사용하는 경우이 목적을 달성하기 위해 100 명의 대표자를 만들어야합니다. –

+0

다른 개체를 만들 수있는 단순한 무언가를 원할뿐입니다. 생성 될 오브젝트는 데이터 컨테이너 일 뿐이며 논리를 포함하지 않습니다. 아직도 틀린가요? –

+0

@LeandroSoares 왜 100 명 이상의 대의원이 필요합니까? – Evk