2014-05-25 2 views
1

하나의 클래스에서 많은 개체 멤버를 초기화하는 모범 사례에 대한 질문이 있습니다. 내가 자주 참조 및 생성자 주입 사용하고 있습니다 곳이 질문의 배경이 포함 된 프로젝트입니다 :초기화 도구 목록에서 많은 개체 멤버 변수 초기화

class ComponentA 
{ 
public: 
    ComponentA(SomeComponent1& dependency1, SomeComponent2& dependeny2) 

private: 
    /* ... */ 
}; 

가 지금은 ComponentA 같은 많은 다른 클래스를했습니다 상상을하고는 하나 개의 클래스에서 인스턴스화 할 필요가 :

class Layer 
{ 
private: 
    ComponentA componentA; // Composition 
    /* ...and many other components */ 

public: 
    Layer(SomeComponent1& firstDepOfA, SomeComponent2& secondDepOfA, ...) : 
     componentA(firstDepOfA, secondDepOfA), /* other components */ 
}; 
내가 복잡성을 줄이기 위해 빌더 패턴의 생각

:

class Layer 
{ 
private: 
    ComponentA componentA; // Composition 
    /* ...and many other components */ 

    /* now private */ 
    Layer(SomeComponent1& firstDepOfA, SomeComponent2& secondDepOfA, ...) : 
     componentA(firstDepOfA, secondDepOfA), /* other components */ 

public: 
    ComponentAIntf& getComponentA (...); 

    class Builder 
    { 
    private: 
    SomeComponent1* firstDepOfA; 
    SomeComponent2* secondDepOfA; 
    /* other dependencies/constructor parameters */ 

    public: 
    /* returns Builder, because we want a fluent api */ 
    Builder& setFirstDepOfA(SomeComponent1* dep) {firstDepOfA = dep; return *this;} 
    Builder& setSecondDepOfA(SomeComponent2* dep) {secondDepOfA = dep; return *this;} 

    Layer& build() 
    { 
     /* check parameters */ 
     ... 

     /* create instance, constructor will be called once when scope is entered */ 
     static Layer layer(/* parameters */); 
     return layer; 
    } 
    } 
}; 

빌더 클래스의 가장 큰 단점은의 생성자 파라미터 구성원 인스턴스가 복제됩니다. 템플릿으로도이 작업을 수행 할 수 있다고 생각하지만 리소스를 찾지 못했습니다. 좋은 예가 있지만 템플릿을 사용하지 않으려 고했습니다. 어떤 도움을 주셔서 감사합니다. 내가 뭔가를 놓친 것 같아 ... 그것은 가능한 것 때문에 당신이 설정 한 종속성의 모든 이전 build 전화를 들어, 위험 할 것 여기 빌더 패턴을 사용하여 미리

답변

0

에서

감사합니다. (명시 적으로 모든 종속성을 지정하지 않고 인스턴스화하는 것을 클래스를 방지하기 위해 생성자 주입을 사용하는 이유 중 하나입니다.)

당신은 LayerComponentA를 주입하기보다는 직접적 의존도를 만들 수 있습니다. 예를 들어 : 의존성 주입을 사용하는 경우

class Layer 
{ 
private: 
    ComponentA& componentA; // Composition 
    /* ...and many other components */ 

public: 
    Layer(ComponentA& componentA, ...) : 
     componentA(componentA), /* other components */ 
}; 

, 당신은 궁극적으로 당신이 실제로 개체 그래프를 빌드 composition root이 있어야합니다. (의존성 주입의 모든 실제로 발생하는 곳이다.)

당신이, 당신은 공장에 대한 책임을 위임 고려할 수 있습니다 수요에 ComponentA를 인스턴스화해야하는 경우 : 대답 및 링크에 대한

class ComponentFactory 
{ 
private: 
    SomeComponent1* firstDepOfA; 
    SomeComponent2* secondDepOfA; 
    /* other dependencies/constructor parameters */ 

public: 
    ComponentFactory(SomeComponent1* firstDepOfA, SomeComponent2* secondDepOfA, ...) : 
     firstDepOfA(firstDepOfA), secondDepOfA(secondDepOfA), ... 
    { 
    } 

    ComponentA CreateComponentA() 
    { 
     return ComponentA(firstDepOfA, secondDepOfA); 
    } 

    ... 
}; 

class Layer 
{ 
private: 
    ComponentFactory& componentFactory; // Composition 
    /* ...and many other components */ 

public: 
    Layer(ComponentFactory& componentFactory, ...) : 
     componentFactory(componentFactory), /* other components */ 

    void DoSomethingThatUsesComponentA() 
    { 
     ComponentA = componentFactory.CreateComponentA(); 
     ... 
    } 
}; 
+0

감사합니다 . 내 예제의 build() 메소드는 모든 매개 변수를 검사하고 불일치가 있으면 오류를 던집니다 (모든 포인터를 NULL로 설정하는 빌더 클래스의 생성자를 잊어 버렸습니다). 링크를 이해하는 한, 내 컴포지션 루트는 모든 구성 요소를 인스턴스화하는 main() 메서드가 될 것입니다 ... – pr0d1g1

+0

@ pr0d1g1 그래, 모든 매개 변수가 설정되었는지 확인하는 방법은 빌드 메서드에 적합합니다. 하지만 그 검사는 실행시에 수행됩니다 (반면 생성자 삽입은 컴파일 타임에이 검사를 수행 할 수 있습니다). 그리고 당신은 당신의'main' 인 합성 루트에 대해 (또는 가능한 한 가깝게 - 합성 루트에 생성 된 공장에 의해 생성되는 것처럼) 맞습니다. – Lilshieste