Wstrzykiwanie zależności: w którym momencie mogę utworzyć nowy obiekt?

13

Refaktoryzuję aplikację PHP i staram się mieć jak najwięcej zastrzyku zależności (DI).

Czuję, że dobrze rozumiem, jak to działa, i z pewnością widzę, że moje zajęcia stają się o wiele szczuplejsze i bardziej solidne.

Refaktoryzuję, aby móc wstrzykiwać zależność, zamiast tworzyć nowy obiekt w klasie, ale w pewnym momencie będę musiał utworzyć niektóre obiekty, to znaczy użyć przerażającego newsłowa kluczowego.

Problem, na który teraz natrafiłem, polega na tym, w którym momencie mogę rzeczywiście tworzyć nowe obiekty? Wygląda na to, że skończę w klasie najwyższego poziomu, tworząc mnóstwo nowych obiektów, ponieważ nie ma dokąd pójść. To źle.

Przeczytałem kilka blogów, które używają klas fabrycznych do tworzenia wszystkich obiektów, a następnie wstrzykujesz fabrykę do innych klas. Następnie możesz wywołać metody fabryczne, a fabryka utworzy dla ciebie nowy obiekt.

Moje obawy związane z robieniem tego są teraz, że moje zajęcia fabryczne będą newdarmowe dla wszystkich! Wydaje mi się, że może to być OK, ponieważ są to klasy fabryczne, ale czy są jakieś zasady, których należy przestrzegać, używając wzorca fabrycznego i DI, czy też odchodzę od tego znaku?

Gaz_Edge
źródło
Polecam IoC dla usług i zasad. Do klas lub klas pomocniczych po prostu użyłbym new. Oczywiście istnieje kilka punktów wejścia, w których musisz zadzwonić do kontenera IoC, ale nie powinno ich być wiele. Zazwyczaj konfigurujesz IoC raz, a następnie poprosisz o rozwiązanie jednej klasy na żądanie. W przypadku MVC jest to zazwyczaj kontroler.
CodesInChaos
Wspomniana klasa najwyższego poziomu jest częścią Korzenia Kompozycji. To jest dalekie od zła.
Współczynnik Facio

Odpowiedzi:

12

Po dłuższej przeróbce wydaje się, że (jak wspomniano w komentarzu powyżej) klasa najwyższego poziomu, o której mówiłem, nazywa się Kompozycja Korzeń .

Rzeczywiście wydaje się, że jest to zaakceptowane rozwiązanie, aby dodać tworzenie wszystkich obiektów w tym składzie głównym (lub odwoływać się do kontenera IoC stąd).

Moim pierwotnym problemem było to, że ta klasa najwyższego poziomu byłaby trochę bałaganem. Jest to do pewnego stopnia prawdziwe, ale nasi profesjonaliści ważą wady. Na przykład widzę, że poprawiono czytelność, testowalność i łatwość konserwacji wszystkich innych klas.

Klasa najwyższego poziomu może być nieco niechlujna, zaśmiecona newi, set_property()ale muszę powiedzieć, że wolę mieć cały ten kod w jednym miejscu, niż rozproszona po innych klasach

Kolejna przydatna strona omawiająca wyniki wydajności tej metody tutaj

Gaz_Edge
źródło
1
+1, ponieważ nigdy wcześniej nie słyszałem o „Korzeniu kompozycji”.
c_maker,
2

Klasa Fabryki będzie neww nim zasypana. Byłoby to tworzenie dowolnego obiektu, o który prosisz, i prawdopodobnie zależności tego obiektu. Ponieważ zadaniem fabryk jest utworzenie odpowiedniego obiektu dla ciebie neww tej klasie, nie jest złą rzeczą.

DI jest tak, że masz luźno sprzężoną konstrukcję. Możesz wprowadzać zmiany w aplikacji, zmieniając zależność zapewnianą dla każdego obiektu. Dzięki temu Twoja aplikacja jest elastyczna, rozszerzalna i łatwa do przetestowania.

Na najwyższym poziomie będziesz mieć kod, który utworzy instancję kilku fabryk, skonfiguruje połączenia z usługami i wyśle ​​odpowiedź. Będzie zawierał sporo newwywołań statycznych w celu utworzenia instancji obiektów niezbędnych dla twojej aplikacji. To właśnie tam należy.

Schleis
źródło
-2

Moje dwa centy tutaj:

Refaktoryzuję aplikację php i próbuję zrobić zastrzyk zależności w miarę możliwości

Nie określasz, czy używasz struktury wstrzykiwania zależności. Myślę, że zdecydowanie powinieneś. Użyj czegoś, co daje ci potrzebne funkcje: /programming/9348376/guice-like-dependency-injection-frameworks-in-php .

Problem, na który teraz natrafiłem, polega na tym, w którym momencie mogę rzeczywiście tworzyć nowe obiekty? Wygląda na to, że skończę w klasie najwyższego poziomu, tworząc mnóstwo nowych obiektów, ponieważ nie ma dokąd pójść. To źle.

Zwykle używasz konfiguracji lub centralnego punktu do tworzenia instancji początkowych obiektów tworzących twoją aplikację. Kontener stworzy dla ciebie obiekty.

Następnie uzyskujesz dostęp do obiektów (usług, dostawców, kontrolerów ...) za pośrednictwem kontenera IoC. W razie potrzeby w przejrzysty sposób utworzy dla Ciebie obiekt lub poda odniesienie do odpowiedniej istniejącej instancji.

Oczywiście wewnątrz konkretnej implementacji obiektów możesz tworzyć instancje innych obiektów, na których nie potrzebujesz DI (struktury danych, typy niestandardowe itp.), Ale to normalne programowanie.

Przeczytałem kilka blogów, które używają klas fabrycznych do tworzenia wszystkich obiektów, a następnie wstrzykujesz fabrykę do innych klas. Następnie możesz wywołać metody fabryczne, a fabryka utworzy dla ciebie nowy obiekt.

Zwykle używasz fabryki, jeśli chcesz, aby środowisko IoC tworzyło niektóre obiekty IoC w twoich fabrykach (jest to potrzebne, gdy tworzenie konkretnego obiektu wymaga dodatkowej pracy). Jeśli możesz po prostu utworzyć swoje obiekty za pomocą „new Object ()” i ustawić niektóre właściwości, niekoniecznie chcesz użyć wzorca fabrycznego.

Innymi słowy, powiedziałbym, że użycie wzorca Factory dla klasy lub grupy klas zależy od tego, jak chcesz modelować te klasy, a nie od tego, czy używasz DI (chyba że twoja implementacja DI wyraźnie wymaga fabryk, co jest niezwykłe).

Skonfigurujesz również swoją strukturę IoC, aby korzystać z fabryki, gdy korzystasz z biblioteki innej firmy, która już wymaga użycia fabryki. W takim przypadku nie masz nad tym kontroli i musisz powiedzieć swojemu kontenerowi IoC: „hej, kiedy proszę o jeden z tych interfejsów, musisz skorzystać z tej fabryki, aby zapewnić mi odpowiednią instancję”.

Moje obawy związane z robieniem tego są teraz, że moje zajęcia fabryczne staną się zupełnie nowe dla wszystkich! Myślę, że może to być w porządku, ponieważ są to klasy fabryczne, ale czy są jakieś zasady, których należy przestrzegać, gdy używam fabrycznego wzorca i DI, czy też idę daleko od znaku.

W tym przypadku wydaje się, że nie musisz używać wzorców fabrycznych dla tych obiektów / usług / kontrolerów / czegokolwiek, i możesz po prostu skonfigurować IoC, aby utworzyć instancję z „nową” odpowiednią klasą i wstrzyknąć wszystko inne.

Mam nadzieję, że to pomoże.

jjmontes
źródło
dzięki za odpowiedź, ale z pewnością kontener IoC to „klasa najwyższego poziomu”, o której mówiłem. Jeśli mogę tylko tam tworzyć obiekty, to będzie właściwy bałagan.
Gaz_Edge
4
doing DI manually beats the whole purpose of using an Inversion of Control container- Jeśli przez to rozumiesz „... który centralizuje twoje zależności w pliku konfiguracyjnym”, to masz rację, ponieważ tak naprawdę to wszystko robi kontener IoC. Prawdziwym celem DI jest odsprzęganie i możesz to zrobić, podając swoje zależności w metodzie konstruktora. W tym celu wcale nie potrzebujesz frameworka DI.
Robert Harvey
mmm, nie tworzysz obiektów, pytasz o nie kontener IoC (z dowolnego miejsca, w którym chcesz) lub używasz wstrzykiwania pól / argumentów, aby twoje klasy były automatycznie wstrzykiwane odpowiednim klasom, tworzonym zawsze przez kontener IoC.
jjmontes
1
Zgodziłbym się, że potrzebujesz ram dla bardzo dużych aplikacji. Wiele aplikacji nie jest tak dużych i nie korzysta z dodatkowej złożoności korzystania ze środowiska DI.
Robert Harvey
2
Nie powiedziałem, że tak było. Powiedziałem po prostu, że nie potrzebujesz do tego pojemnika DI.
Robert Harvey