Su objetivo es ser una respuesta complementaria a Doc Brown, y también responder a los comentarios no respondidos de Dinaiz que todavía están relacionados con la Pregunta.
Lo que probablemente necesite es un marco para hacer DI. Tener jerarquías complejas no significa necesariamente un mal diseño, pero si tiene que inyectar un TimeFactory de abajo hacia arriba (de A a D) en lugar de inyectar directamente a D, entonces probablemente haya algo mal con la forma en que está haciendo la Inyección de dependencia.
Un singleton? No, gracias. Si solo necesita una isancia, haga que se comparta en el contexto de su aplicación (el uso de un contenedor de IoC para DI como Infector ++ solo requiere vincular TimeFactory como una sola istance), este es el ejemplo (C ++ 11 por cierto, pero entonces C ++. Tal vez mover a C ++ 11 ya? Obtiene la aplicación sin fugas de forma gratuita):
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>();
Ahora, lo bueno de un contenedor de IoC es que no necesita pasar la fábrica de tiempo a D. Si su clase "D" necesita fábrica de tiempo, simplemente coloque fábrica de tiempo como parámetro de construcción para la clase 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
como ves, inyectas TimeFactory solo una vez. ¿Cómo usar "A"? Muy simple, cada clase se inyecta, se construye en general o se certifica con una fábrica.
auto myA1 = ioc.build<A>(); //A is not "single" so many different istances
auto myA2 = ioc.build<A>(); //can live at same time
cada vez que cree la clase A, se inyectará automáticamente (dependencia perezosa) todas las dependencias hasta D y D se inyectará con TimeFactory, por lo que al llamar solo 1 método tendrá lista su jerarquía completa (e incluso las jerarquías complejas se resuelven de esta manera eliminar MUCHO código de placa de caldera): no tiene que llamar "nuevo / eliminar" y eso es muy importante porque puede separar la lógica de la aplicación del código de pegamento.
D puede crear objetos de tiempo con información que solo D puede tener
Eso es fácil, su TimeFactory tiene un método de "creación", luego use una firma diferente "crear (parámetros)" y listo. Los parámetros que no son dependencias a menudo se resuelven de esta manera. Esto también elimina el deber de inyectar cosas como "cadenas" o "enteros" porque eso solo agrega placa de caldera adicional.
¿Quién crea a quién? El contenedor de IoC crea istances y fábricas, las fábricas crean el resto (las fábricas pueden crear diferentes objetos con parámetros arbitrarios, por lo que realmente no necesita un estado para las fábricas). Todavía puede usar las fábricas como envoltorios para el Contenedor de IoC: en general, Inyectar en el Contenedor de IoC es muy malo y es lo mismo que usar un localizador de servicios. Algunas personas resolvieron el problema envolviendo el contenedor de IoC con una fábrica (esto no es estrictamente necesario, pero tiene la ventaja de que el contenedor resuelve la jerarquía y que todas sus fábricas se vuelven aún más fáciles de mantener).
//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);
}
Tampoco abuses de la inyección de dependencia, los tipos simples pueden ser miembros de la clase o variables locales. Esto parece obvio, pero vi personas inyectando "std :: vector" solo porque había un marco DI que lo permitía. Recuerde siempre la ley de Demeter: "Inyecte solo lo que realmente necesita inyectar"