이는 Doc Brown에 대한 보완 적 답변이자 여전히 질문과 관련된 Dinaiz의 답변되지 않은 의견에 답변하는 것을 목표로합니다.
아마도 필요한 것은 DI를 수행하기위한 프레임 워크입니다. 복잡한 계층 구조가 반드시 나쁜 설계를 의미하는 것은 아니지만 D에 직접 주입하는 대신 TimeFactory 상향식 (A에서 D로)을 주입해야하는 경우 Dependency Injection을 수행하는 방식에 문제가있을 수 있습니다.
싱글 톤? 괜찮습니다. Instanceor ++와 같은 DI에 IoC 컨테이너를 사용하면 TimeFactory를 단일 istance로 바인딩하기 만하면됩니다.이 예제는 C ++ 11이지만 C ++입니다. C ++ 11을 이미 사용하고 계십니까?
Infector::Container ioc; //your app's context
ioc.bindSingleAsNothing<TimeFactory>(); //declare TimeFactory to be shared
ioc.wire<TimeFactory>(); //wire its constructor
// if you want to be sure TimeFactory is created at startup just request it
// (else it will be created lazily only when needed)
auto myTimeFactory = ioc.buildSingle<TimeFactory>();
이제 IoC 컨테이너의 장점은 시간 팩토리를 D까지 전달할 필요가 없다는 것입니다. 클래스 "D"에 타임 팩토리가 필요한 경우, 시간 팩토리를 클래스 D의 생성자 매개 변수로 두십시오.
ioc.bindAsNothing<A>(); //declare class A
ioc.bindAsNothing<B>(); //declare class B
ioc.bindAsNothing<D>(); //declare class D
//constructors setup
ioc.wire<D, TimeFactory>(); //time factory injected to class D
ioc.wire<B, D>(); //class D injected to class B
ioc.wire<A, B>(); //class B injected to class A
보시다시피 TimeFactory를 한 번만 주입하십시오. "A"를 사용하는 방법? 매우 간단합니다. 모든 수업은 기본으로 주입되거나 공장에서 생산됩니다.
auto myA1 = ioc.build<A>(); //A is not "single" so many different istances
auto myA2 = ioc.build<A>(); //can live at same time
클래스 A를 만들 때마다 최대 D까지의 모든 종속성으로 자동 (지연 한 istantiation) 주입되고 D는 TimeFactory로 주입되므로 1 개의 메소드 만 호출하면 완전한 계층 구조가 준비됩니다 (심지어 복잡한 계층 구조도이 방법으로 해결됩니다) 보일러 플레이트 코드를 많이 제거)
D는 D 만 가질 수있는 정보로 Time 객체를 만들 수 있습니다
TimeFactory에 "create"메소드가 있고 다른 서명 "create (params)"를 사용하면됩니다. 종속성이없는 매개 변수는 종종이 방법으로 해결됩니다. 이것은 또한 보일러 플레이트를 추가하기 때문에 "문자열"또는 "정수"와 같은 것을 주입 할 의무를 제거합니다.
누가 누구를 만들어? IoC 컨테이너는 인스턴스와 팩토리를 생성하고 팩토리는 나머지를 생성합니다 (공장은 임의의 매개 변수로 다른 객체를 생성 할 수 있으므로 팩토리의 상태가 실제로 필요하지 않음). 팩토리를 IoC 컨테이너의 래퍼로 계속 사용할 수 있습니다. 일반적으로 IoC 컨테이너의 주입은 매우 나쁘고 서비스 로케이터를 사용하는 것과 같습니다. 일부 사람들은 IoC 컨테이너를 팩토리로 감싸서 문제를 해결했습니다 (이것은 꼭 필요한 것은 아니지만 컨테이너가 계층 구조를 해결하고 모든 팩토리를 유지 관리하기가 더 쉽다는 장점이 있습니다).
//factory method
std::unique_ptr<myType> create(params){
auto istance = ioc->build<myType>(); //this code's agnostic to "myType" hierarchy
istance->setParams(params); //the customization you needed
return std::move(istance);
}
또한 의존성 주입을 남용하지 말고 간단한 유형은 클래스의 멤버 또는 지역 범위 변수 일 수 있습니다. 이것은 명백해 보이지만 사람들이 그것을 허용 한 DI 프레임 워크가 있기 때문에 "std :: vector"를 주입하는 것을 보았다. Demeter의 법칙을 항상 기억하십시오 : "실제로 주입해야하는 것만 주입하십시오"