Ma to być uzupełniającą odpowiedzią na doktora Browna, a także odpowiedzieć na komentarze Dinaiz bez odpowiedzi, które są nadal związane z pytaniem.
Prawdopodobnie potrzebujesz ramy do wykonywania DI. Posiadanie złożonych hierarchii niekoniecznie oznacza zły projekt, ale jeśli musisz wstrzyknąć oddolne TimeFactory (od A do D) zamiast wstrzykiwać bezpośrednio do D, prawdopodobnie jest coś złego w sposobie wykonywania Dependency Injection.
Singleton? Nie, dziękuję. Jeśli potrzebujesz tylko jednej istoty, udostępnij ją w kontekście aplikacji (użycie kontenera IoC dla DI, takiego jak Infector ++, wymaga tylko powiązania TimeFactory jako pojedynczej instancji), oto przykład (C ++ 11 przy okazji, ale tak C ++. Może przenieś do C ++ 11? Otrzymujesz aplikację Leak-Free za darmo):
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>();
Teraz zaletą kontenera IoC jest to, że nie musisz przekazywać fabryki czasu do D. Jeśli twoja klasa „D” potrzebuje fabryki czasu, po prostu ustaw fabrykę czasu jako parametr konstruktora dla klasy 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
jak widzisz, wstrzykujesz TimeFactory tylko raz. Jak używać „A”? Bardzo proste, każda klasa jest wstrzykiwana, budowana w głównej postaci lub zakładana fabrycznie.
auto myA1 = ioc.build<A>(); //A is not "single" so many different istances
auto myA2 = ioc.build<A>(); //can live at same time
za każdym razem, gdy utworzysz klasę A, zostanie ona automatycznie wstrzyknięta (leniwa istnienie) ze wszystkimi zależnościami do D, a D zostanie wstrzyknięta TimeFactory, więc wywołując tylko 1 metodę masz pełną hierarchię (a nawet skomplikowane hierarchie są rozwiązywane w ten sposób usuwając DUŻO kodu płyty kotłowej): Nie musisz dzwonić „nowy / usuń”, a to bardzo ważne, ponieważ możesz oddzielić logikę aplikacji od kodu kleju.
D może tworzyć obiekty Czasu z informacjami, które może posiadać tylko D.
To proste, twój TimeFactory ma metodę „utwórz”, a następnie użyj innej sygnatury „utwórz (parametry)” i gotowe. Parametry bez zależności są często rozwiązywane w ten sposób. Eliminuje to również obowiązek wstrzykiwania rzeczy takich jak „ciągi” lub „liczby całkowite”, ponieważ to po prostu dodaje dodatkową płytę kotła.
Kto tworzy kogo? Kontener IoC tworzy istoty i fabryki, fabryki tworzą resztę (fabryki mogą tworzyć różne obiekty o dowolnych parametrach, więc tak naprawdę nie potrzebujesz stanu dla fabryk). Nadal możesz używać fabryk jako opakowań dla kontenera IoC: ogólnie mówiąc, wstrzykiwanie kontenera IoC jest bardzo złe i jest identyczne z używaniem lokalizatora usług. Niektóre osoby rozwiązały problem, pakując kontener IoC w fabrykę (nie jest to absolutnie konieczne, ale ma tę zaletę, że hierarchia jest rozwiązana przez kontener, a wszystkie fabryki stają się jeszcze łatwiejsze do utrzymania).
//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);
}
Nie nadużywaj również wstrzykiwania zależności, proste typy mogą być po prostu elementami klasy lub zmiennymi o zasięgu lokalnym. Wydaje się to oczywiste, ale widziałem ludzi, którzy wstrzykują „std :: vector” tylko dlatego, że istniała struktura DI, która na to pozwoliła. Zawsze pamiętaj o prawie Demetera: „Wstrzykuj tylko to, czego naprawdę potrzebujesz do wstrzyknięcia”