2010-12-17 6 views
2

나는 엄격한 IoC 패턴을 따르고 나쁜 습관에 빠지지 않도록 노력하고 있습니다.이 코드는 IoC를 올바르게 사용합니까? 여기서 어디로 갈 수 있습니까?

회원 클래스의 생성자에 관련 정보를 모두로드해야합니까?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Net; 
using System.Text; 
using System.Xml.Linq; 
using SharpDIC.Api.Interfaces; 
using SharpDIC.Api.Models; 
using System.Configuration; 

namespace SharpDIC.Api.Concrete 
{ 
    class XmlMemberFinder : IMemberFinder 
    { 
     public IList<Member> FindAllMembers() 
     { 
      using (var webClient = new WebClient()) 
      { 
       for (int i = 0; i < 470000; i++) 
       { 
        string htmlSource = webClient.DownloadString(ConfigurationManager.AppSettings["MemberUrl"] + i); 
        XDocument response = XDocument.Parse(htmlSource); 
        //The member class would parse the XML itself and load it's attributes itself. 
        Member member = new Member(response); 
       } 
      } 
     } 

     public Member FindMember(int memberId) 
     { 
      throw new NotImplementedException(); 
     } 

     public Member FindMember(string memberName) 
     { 
      throw new NotImplementedException(); 
     } 
    } 
} 

당신은 무엇을 할 것? 이것이 가능한 TDD/IoC를 유지하기위한 가장 좋은 해결책은 무엇입니까?

편집 :

괜찮습니까?

using SharpDIC.Api.Models; 

namespace SharpDIC.Api.Interfaces 
{ 
    interface IMemberSource 
    { 
     Member LoadMember(string source); 
    } 
} 

내가 다시 붙어있어, 실제로 뭔가를로드합니까? 실제로 뭔가 작업을하지 않고 인터페이스를 만든 후에 인터페이스를 작성하는 것처럼 느껴집니다.

+0

- 그것은에 조금 걸립니다 그 주위에 머리를 얻을. 당신은 옳은 길을 가고 있습니다 만, LoadMember()는 '소스'를 알지 않아야합니다 - 그것을 구현하는 객체도 마찬가지입니다. 첫 번째 코드 블록에서도 config 문자열을 쿼리하여 소스를 가져옵니다. IMemberSource의 프로덕션 구현도 똑같이 할 것입니다. LoadMember는 아마도 인수가 필요하지 않거나 열거 형을 반환 할 수 있습니까? – n8wrl

+0

이것에 대해 더 생각해보십시오. IMemberSource는 실제로 저장소입니다. DB, XML/웹 서비스, 테스트 용 하드 코딩 된 콜렉션 등 어떤 소스에서 멤버를 얻는 방법을 알고있는 것입니다. – n8wrl

+0

@ n8wrl : 의견을 보내 주셔서 감사합니다. 시간이 걸릴 것입니다. :) 나는이 특별한 문제를 해결했다고 생각한다. 나는 일을 올바르게하고 싶습니다. :피 –

답변

1

EXCELLENT 질문, Sergio! 내가 당신을 위해 부하 않는 'IMemberSource'인터페이스를 정의하는 것이 좋습니다 것입니다. IoC를 통해 주입하십시오. 테스트를 위해 하나를 모의 테스트하여 XmlMemberFinder를 테스트하십시오. 프로덕션에서는 WebClient 작업을 수행합니다.

0

IoC 또는 DI는 모두 개체 작성 자체가 아니라 작업 완료에 필요한 공동 작업자에게 개체를 제공하는 것입니다.

하나의 책임을 지닌 클래스는 이해하기 쉽고 변경하기가 쉽기 때문에, 이렇게하면 단일 책임을 갖는 클래스를 훨씬 쉽게 얻을 수 있습니다.

또한 TDD를 사용하여 코드를 작성한다는 것은 이런 종류의 일이 아주 자연스럽게 일어남을 의미합니다.

나는 당신의 코드가 무엇을하려하는지 정말로 모르겠다. 50 만개의 URL을로드 한 다음 결과를 버리는 것으로 보인다.

어떤 종류의 사용자 저장소를 구현하려고한다고 가정합니다. 시스템의 일부 다른 부분은 어떤 이유로 든이 사용자 저장소가 필요합니다.

DI가이 방법으로 들어가는 방법은 기타 비트의 사용자 저장소를 주입하는 것입니다.

하면 인터페이스를 가지고 상상 :

(구문이 100 %되지 않을 수도 있습니다 내가 정말 교류 # 사람이야) 당신의 여러 구현을 작성할 수 있습니다

이제

public interface UserStore { Member findMember(string memberId); }

당신의 사용자 저장소! - 첫째로 웹에 간다.

public class HttpUserStore : UserStore {

private final URI baseUri; 

    public HttpUserStore(URI baseuri) { 
    this.uri = baseUri; 
    } 

    public Member findMember(string memberId) { 
     string uri = constructUriFor(memberId); 
     // go get the xml 
     return unmarshal(xml); 
    } 
} 

또는 당신은 테스트를 작성할 수 있습니다. 둘 다 인터페이스를 구현하고 그것이 부여 된 하나 모르고 사용하는 클래스 -

public class StubUserStore : UserStore {

public Member findMember(string memberId) { 
     return new MemberBuilder() 
        .withMemberId(memberId) 
        .withName("Joe Bloggs") 
        .build(); 
    } 
} 

이제 두 가지 구현이있다.그것은 무엇이 주어 졌는지를 알지만 멤버를 찾는 데 사용할 수 있습니다. 따라서 의존성이 주입되었습니다.

예를 들어 웹 로그인 모듈이 사용자 로그인을 위해 UserStore를 사용해야한다고 가정 해보십시오.

우리는 좋아 인스턴스화 수 :

UserStore userStore = new HttpUserStore(new URI("https://secret.stuff"); 
    HttpLoginModule loginModule = new BasicAuthLoginModule(userStore); 

    WebSite webSite = new SuperWebSite(loginModule); 

또는 같은

가 :
UserStore userStore = new StubUserStore(); 
    HttpLoginModule loginModule = new BasicAuthLoginModule(userStore); 
    WebSite webSite = new SuperWebSite(loginModule); 

또는 같은

가 :

고객님의 불만, 세르지오을 이해
UserStore userStore = new StubUserStore(); 
    HttpLoginModule loginModule = new X509LoginModule(userStore); 
    WebSite webSite = new SuperWebSite(loginModule); 
관련 문제