2013-02-28 4 views
3

다른 클라이언트에서 하나의 인터페이스로 다른 구현을 사용하는 방법이 궁금합니다. 다음은 상황의 예입니다.IoC 컨테이너가있는 다른 장소에서 다른 구현을 사용하는 방법

public interface IRandomIntGenerator 
{ 
    int Generate(); 
} 

public class SimpleRandomIntGenerator : IRandomIntGenerator 
{ 
    public int Generate() 
    { 
     return new Random().Next(); 
    } 
} 

public class CryptoServiceProviderRandomIntGenerator : IRandomIntGenerator 
{ 
    public int Generate() 
    { 
     var generator = new RNGCryptoServiceProvider(); 
     byte[] bytes = new byte[4]; 
     generator.GetBytes(bytes); 
     return BitConverter.ToInt32(bytes, 0); 
    } 
} 

그런 다음 특정 구현에 대해 알고 싶지 않은 두 명의 고객이 있습니다. 하나는 로그인 코드를 생성하고 다른 하나는 배열의 임의 항목을 선택합니다.

public class LogInCodeGenerator 
{ 
    private readonly IRandomIntGenerator randomIntGenerator; 

    public LogInCodeGenerator(IRandomIntGenerator randomIntGenerator) 
    { 
     this.randomIntGenerator = randomIntGenerator; 
    } 

    public string GenerateCode(int length) 
    { 
     var builder = new StringBuilder(length); 
     for (int i = 0; i < length; i++) 
      builder.Append(randomIntGenerator.Generate() % 10); 
     return builder.ToString(); 
    } 
} 

public class RandomArrayItemChoose 
{ 
    private readonly IRandomIntGenerator randomIntGenerator; 

    public RandomArrayItemChoose(IRandomIntGenerator randomIntGenerator) 
    { 
     this.randomIntGenerator = randomIntGenerator; 
    } 

    public string Choose(string[] arr) 
    { 
     return arr[randomIntGenerator.Generate() % arr.Length]; 
    } 
} 

가 나는 LogInCodeGenerator에 대한 RandomArrayItemChoose에 대한 SimpleRandomIntGeneratorCryptoServiceProviderRandomIntGenerator를 사용할 것이다 그런 방법으로 IoC 컨테이너를 구성 할.

.NET에서 널리 사용되는 IoC 컨테이너에서이 작업을 수행 할 수있는 방법이 있습니까? 나는 윈저성에 특히 관심이 있습니다.

답변

3

그럼 난 특정 구현에 대해 알고 싶지 않아 두 클라이언트를했습니다.

디자인에 다소 모호한 것처럼 보입니다. 이러한 클라이언트는 정확한 구현에 관심이 없을 수도 있지만 시스템에 어떤 종류의 요구 사항이있는 것으로 보이며 LogInCodeGenerator은 암호 난수로 작동해야합니다.

시스템을 안전하게 유지하려면이 요구 사항이므로 이에 대한 디자인을 명시 적으로 지정하는 것이 좋습니다. 즉, 여기에 대한 두 개의 별도의 계약을 이야기 :

interface IRandomIntGenerator { } 

interface ICryptographicRandomIntGenerator { } 

이는이 디자인이 훨씬 간단하여 DI 구성을 만드는에서이 모호성을 제거 훨씬 명확하게 코드의 의도 만들 않습니다뿐만 아니라.

+0

나는 IRandomIntGenertor''에서 상속 빈 인터페이스 결국했습니다. – Kirill

+0

@Kirill : 한 줄의 코드를 저장합니다. 그만한 가치가 있니? – Steven

+0

이것은 하나의 예일뿐입니다. 대부분의 경우 인터페이스에는 여러 가지 방법이 있습니다. 그러나, 나는 아직도 그것을 더러운 해킹처럼 느낀다. – Kirill

1

등록 된 인스턴스의 이름을 지정한 다음 이름을 사용하여 액세스 할 수 있습니다. 귀하의 경우, 귀하의 질문을 이해할 경우 해결 된 인스턴스를 요청하는 클래스를 기반으로 다른 주입이 필요합니다. 등록 된 인스턴스의 이름을 요청한 클래스의 유형 이름으로 지정할 수 있습니다.

수동 resolve 인스턴스해야합니다 :

IRandomIntGenerator generator = container.Resolve<IRandomIntGenerator>(GetType().Name); 
4

윈저의 서비스 재정의를 사용하십시오. Windsor Docs에서 "사용할 종속성을위한 구성 요소 제공"절을 참조하십시오.

1

그냥 명시 적으로 선언 종속 관계 :

Component. 
    For<IRandomIntGenerator>(). 
    ImplementedBy<SimpleRandomIntGenerator>(). 
    Named("SimpleRandomIntGenerator"), 
Component. 
    For<IRandomIntGenerator>(). 
    ImplementedBy<CryptoServiceProviderRandomIntGenerator>(). 
    Named("CryptoServiceProviderRandomIntGenerator"), 
Component. 
    For<RandomArrayItemChoose>(). 
    DependsOn(Dependency. 
     OnComponent("randomIntGenerator", "SimpleRandomIntGenerator")), 
Component. 
    For<LogInCodeGenerator>(). 
    DependsOn(Dependency. 
     OnComponent("randomIntGenerator", "CryptoServiceProviderRandomIntGenerator")), 
관련 문제