2011-01-03 2 views
1

가진 객체를 생성 I 종속성 필요 객체가 인수 위해서Structuremap하고는 초기 상태

public class FootballLadder 
{ 
    public FootballLadder(IMatchRepository matchRepository, int round) 
    { 
     // set initial state 
     this.matchRepo = matchRepository; 
     this.round = round; 
    } 

    public IEnumerable<LadderEntry> GetLadderEntries() 
    { 
     // calculate the ladder based on matches retrieved from the match repository 
     // return the calculated ladder 
    } 

    private IMatchRepository matchRepo; 
    private int round; 
} 

주입 한 I 자체 호출 GetLadderEntries로 라운드 파라미터를 전달할 수 있다고 가정 할 수 있습니다.

StructureMap을 사용하여 IMatchRepository에 종속성을 주입하고 초기 상태를 설정하려면 어떻게해야합니까? 아니면 프레임 워크에 맞서 싸우는 것이 코드가 리팩터링되어야한다는 신호입니까?

답변

1

대부분의 DI 프레임 워크를 사용하면 생성자에 Spinon과 같은 프리미티브를 삽입 할 수 있습니다. 가능한 경우 복잡한 구성이 필요하지 않도록 코드를 리팩터링하려고합니다. 종종 이것은 최소한의 놀라움으로 (분당 WTF 수가 적음) 내 응용 프로그램 코드를 가장 이해할 수있게 만듭니다 .-)). 때로는 복잡한 구성으로 인해 응용 프로그램 코드가 더 간단해질 수 있기 때문에이를 조심스럽게 균형 조정해야합니다. 여기

는 리팩토링에 대한 몇 가지 가능한 제안 사항 :

public interface IFootballLadderFactory 
{ 
    FootballLadder CreateNew(int round); 
} 

이 방법 : 클라이언트가 round 값을 제어해야하는 경우 공장 유용 사용

:

1) 공장을 사용하여 IFootballLadderFactory을 삽입하고 고객이 전화하도록 허용 할 수 있습니다.

당신은 생성자에서 round 인수를 제거하고 GET/설정 속성에서 변경할 수 있습니다 :

2) 속성을 사용합니다.

public class CastleFootballLadderFactory : IFootballLadderFactory 
{ 
    public IWindsorContainer Container; 

    public FootballLadder CreateNew(int round) 
    { 
     var ladder = this.Container.Resolve<FootballLadder>(); 
     ladder.Round = round; 
     return ladder; 
    } 
} 

또는 클라이언트 수 :

public class FootballLadder 
{ 
    private IMatchRepository matchRepo; 

    public FootballLadder(IMatchRepository matchRepository) 
    { 
    } 

    public int Round { get; set; } 
} 

그리고 인스턴스에 대한 IFootballLadderFactory의 구현과 같을 수 있습니다 : 클라이언트가 round 값을 제어 할 수 있어야합니다 또는 공장을 사용하는 경우 때 유용 둘 다 Round 속성을 설정하십시오.

public class Client 
{ 
    public Client(FootballLadder ladder) 
    { 
     ladder.Round = 3; 
    } 
} 

이 마지막 예에주의하십시오. 클라이언트는 대개 종속성의 수명을 신경 쓸 필요가 없습니다. 이 경우 주입 된 종속성의 상태가 변경됩니다. 이렇게하면이 종속성의 수명을 변경하지 못하게됩니다.이 경우 ladder 인스턴스의 상태가 클라이언트의 발 밑에서 변경 될 수 있기 때문입니다. 이 외에도 FootballLadder 클래스는 Round이 설정되지 않은 경우 InvalidOperationException을 던져야합니다. 나는 그런 체크가 훌륭하고 깨끗하다고 ​​생각하지만 좀 더 코드를 작성하게한다. 스핀 온이 썼던 것처럼, 당신이 IRoundProvider을 구현할 수

, 대신에 구성에서 사용, 당신은 생성자 인수로 사용할 수 있습니다

3)는 FootballLadder 생성자에 IRoundProvider를 주입한다.

public class FootballLadder 
{ 
    private IMatchRepository matchRepo; 
    private int round; 

    public FootballLadder(IMatchRepository matchRepository, 
     IRoundProvider roundProvider) 
    { 
     this.round = roundProvider.GetRound(); 
    }   
} 

4) DI 구성에 대한 구체적인 하위 유형을 만듭니다 다음과 같이

public class DIFootballLadder : FootballLadder 
{ 
    private const int Round = 3; 

    public DIFootballLadder(IMatchRepository matchRepository) 
     : base(matchRepository, Round) 
    { 
    } 
} 

지금 당신이 그것을 등록 할 수 있습니다

이의
x.For<FootballLadder>().Use<DIFootballLadder>(); 

단점은 너야 이 여분의 코드는 일반 구성 코드입니다. 그 외에도 FootballLadder의 종속성이 변경되면 DIFootballLadder도 변경해야합니다.

이 정보가 도움이되기를 바랍니다.

+0

감사합니다. 스티븐은 매우 도움이됩니다. 나는 세터 사용에 대해 생각해 보았지만 강제적으로 사용하도록 강요했다. 당신은 주입으로 생성 된 Factory를 사용할 수 있었고 클라이언트로 돌아 오기 전에 속성을 설정하는 것이 옳았다. – Simon

2

항상 기본값에 대해 생성자 매개 변수를 사용할 수 있습니다. 나는 sqlconnection의 기본 인스턴스에 대해 다음을 사용했다.

this.For<SqlConnection>().Use(c => new SqlConnection(ConfigurationManager.ConnectionStrings["conn"].ConnectionString)); 

다른 방법도 있지만 머리 꼭대기에서 기억하지 못합니다.

편집 : 편집 할 수있는 또 다른 방법이 있습니다. http://www.theabsentmindedcoder.com/2010/05/structure-map-26-constructor-arguments.html

x.For<MatchRepository>().Use<MatchRepository>(); 
x.For<IFootballLadder>().Use<FootballLadder>() 
    .Ctor<int>("round") 
    .Is(3); 

라운드의 값이 법에서 결정되었다 경우 람다 표현식을 지정할 수는이 수 있도록

.Is(c => c.GetInstance<IRoundProvider>().GetRound()) 

희망 같은 값을로드 : 여기에서 이것을 발견 감각. 그러나 네 질문에 대답하기 위해서는 가능하고 꽤 쉽습니다.

+0

감사합니다. 의견과 링크 모두에 도움이됩니다. 좀 더 생각을해야하지만, 좋은 시작 이니 – Simon