Questo vuole essere una risposta complementare a Doc Brown, e anche rispondere ai commenti senza risposta di Dinaiz che sono ancora legati alla Domanda.
Ciò di cui hai probabilmente bisogno è un framework per fare DI. Avere gerarchie complesse non significa necessariamente una progettazione errata, ma se si deve iniettare un bottom-up TimeFactory (da A a D) invece di iniettare direttamente in D allora probabilmente c'è qualcosa di sbagliato nel modo in cui si sta facendo Dependency Injection.
Un singleton? No grazie. Se hai bisogno di una sola istanza, rendila condivisa nel tuo contesto applicativo (utilizzando un contenitore IoC per DI come Infector ++ richiede solo il binding di TimeFactory come istanza singola), ecco l'esempio (C ++ 11 a proposito, ma così C ++. a C ++ 11 già? Si ottiene l'applicazione Leak-Free gratuitamente):
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>();
Ora il punto buono di un contenitore IoC è che non è necessario passare il tempo in fabbrica a D. se la classe "D" ha bisogno di una produzione a tempo, inserire semplicemente la produzione di fabbrica come parametro costruttore per la classe 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
come ti vedi iniettare TimeFactory solo una volta. Come usare "A"? Molto semplice, ogni classe viene iniettata, costruita nel principale o istanziata con una fabbrica.
auto myA1 = ioc.build<A>(); //A is not "single" so many different istances
auto myA2 = ioc.build<A>(); //can live at same time
ogni volta che crei la classe A sarà automaticamente (lazy instantiation) iniettata con tutte le dipendenze fino a D e D verrà iniettata con TimeFactory, quindi chiamando solo 1 metodo avrai la tua gerarchia completa pronta (e anche le gerarchie complesse sono risolto in questo modo rimuovendo un sacco di codice piastra della caldaia): non devi chiamare "nuovo / cancella" e questo è molto importante perché puoi separare la logica dell'applicazione dal codice della colla.
D can create Time objects with informations that only D can have
È facile, il tuo TimeFactory ha un metodo "crea", quindi usa solo una firma diversa "create (params)" e hai finito. I parametri che non dipendono sono spesso risolti in questo modo. Questo elimina anche il dovere di iniettare cose come "stringhe" o "interi" perché questo aggiunge solo un piatto di caldaia aggiuntivo.
Chi crea chi? Il contenitore IoC crea istanze e fabbriche, le fabbriche creano il resto (le fabbriche possono creare oggetti diversi con parametri arbitrari, quindi non hai realmente bisogno di uno stato per le fabbriche). È ancora possibile utilizzare le fabbriche come wrapper per il contenitore IoC: in generale, injectin il contenitore IoC è molto cattivo ed è lo stesso dell'utilizzo di un localizzatore di servizi. Alcune persone hanno risolto il problema avvolgendo il Contenitore IoC con una fabbrica (questo non è strettamente necessario, ma ha il vantaggio che la gerarchia è risolta dal Container e tutte le tue fabbriche diventano ancora più facili da mantenere).
//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);
}
Inoltre non abusare delle dipendenze, i tipi semplici possono essere solo membri di classe o variabili locali. Questo sembra ovvio, ma ho visto persone iniettare "std :: vector" solo perché c'era un framework DI che lo permetteva. Ricorda sempre la legge di Demeter: "Inietta solo ciò che hai veramente bisogno di iniettare"