Dies zielt darauf ab, eine ergänzende Antwort auf Doc Brown zu sein und auch auf unbeantwortete Kommentare von Dinaiz zu antworten, die sich immer noch auf die Frage beziehen.
Was Sie wahrscheinlich brauchen, ist ein Framework für DI. Komplexe Hierarchien zu haben, bedeutet nicht unbedingt ein schlechtes Design. Wenn Sie jedoch eine TimeFactory-Bottom-up-Methode (von A nach D) verwenden müssen, anstatt direkt in D zu injizieren, liegt wahrscheinlich ein Fehler in der Art und Weise vor, wie Sie die Abhängigkeitsinjektion durchführen.
Ein Singleton? Nein Danke. Wenn Sie nur eine Instanz benötigen, um sie für den gesamten Anwendungskontext freizugeben (Wenn Sie einen IoC-Container für DI wie Infector ++ verwenden, müssen Sie TimeFactory nur als einzelne Instanz binden), sehen Sie sich das folgende Beispiel an (C ++ 11 übrigens, aber C ++. Möglicherweise verschieben zu C ++ 11 erhalten Sie kostenlos die Leak-Free-Anwendung):
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>();
Der Vorteil eines IoC-Containers besteht nun darin, dass Sie die Zeitfactory nicht an D übergeben müssen. Wenn Ihre Klasse "D" eine Zeitfactory benötigt, geben Sie einfach die Zeitfactory als Konstruktorparameter für die Klasse D ein.
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
Wie Sie sehen, spritzen Sie TimeFactory nur einmal. Wie benutze ich "A"? Ganz einfach, jede Klasse wird eingespritzt, in der Hauptleitung gebaut oder mit einer Fabrik verbunden.
auto myA1 = ioc.build<A>(); //A is not "single" so many different istances
auto myA2 = ioc.build<A>(); //can live at same time
Jedes Mal, wenn Sie Klasse A erstellen, werden automatisch alle Abhängigkeiten (Lazy Istantiation) und TimeFactory (D) eingefügt. Wenn Sie also nur 1 Methode aufrufen, haben Sie Ihre gesamte Hierarchie bereit (und auch komplexe Hierarchien werden auf diese Weise gelöst) Entfernen VIELES Kesselplattencodes): Sie müssen nicht "new / delete" aufrufen, und das ist sehr wichtig, da Sie die Anwendungslogik vom Klebercode trennen können.
D kann Zeitobjekte mit Informationen erstellen, die nur D haben kann
Das ist ganz einfach, Ihre TimeFactory verfügt über eine "create" -Methode, verwenden Sie dann einfach eine andere Signatur "create (params)" und fertig. Parameter, die keine Abhängigkeiten darstellen, werden häufig auf diese Weise aufgelöst. Dadurch entfällt auch die Pflicht zum Injizieren von Elementen wie "Strings" oder "Integer", da nur eine zusätzliche Kesselplatte hinzugefügt wird.
Wer schafft wen? Der IoC-Container erstellt Bestände und Fabriken, die Fabriken erstellen den Rest (Fabriken können verschiedene Objekte mit beliebigen Parametern erstellen, sodass Sie keinen Status für Fabriken benötigen). Sie können die Fabriken weiterhin als Wrapper für den IoC-Container verwenden: Im Allgemeinen ist das Injizieren in den IoC-Container sehr schlecht und entspricht der Verwendung eines Service-Locators. Einige Leute haben das Problem gelöst, indem sie den IoC-Container mit einer Fabrik umhüllt haben (dies ist nicht unbedingt erforderlich, hat aber den Vorteil, dass die Hierarchie durch den Container gelöst wird und alle Ihre Fabriken noch einfacher zu warten sind).
//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);
}
Missbrauchen Sie auch nicht die Abhängigkeitsinjektion. Einfache Typen können nur Klassenmitglieder oder Variablen mit lokalem Gültigkeitsbereich sein. Dies scheint offensichtlich zu sein, aber ich habe gesehen, wie Leute "std :: vector" injizierten, nur weil es ein DI-Framework gab, das dies erlaubte. Denken Sie immer an Demeters Gesetz: "Injizieren Sie nur, was Sie wirklich brauchen, um zu injizieren"