Jest to podobne do odpowiedzi, za którą głosowano, ale ja chcę myśleć głośno - być może inni też widzą to w ten sposób.
Klasyczny obiekt obiektowy używa konstruktorów do definiowania publicznego kontraktu "inicjującego" dla konsumentów klasy (ukrywanie WSZYSTKICH szczegółów implementacji; aka hermetyzacja). Ten kontrakt może zapewnić, że po utworzeniu instancji będziesz mieć gotowy do użycia obiekt (tj. Żadnych dodatkowych kroków inicjalizacyjnych do zapamiętania (eee, zapomnienia) przez użytkownika).
(konstruktor) DI niezaprzeczalnie przerywa hermetyzację przez wykrwawianie szczegółów implementacji za pośrednictwem tego publicznego interfejsu konstruktora. Dopóki nadal uważamy, że konstruktor publiczny jest odpowiedzialny za zdefiniowanie kontraktu inicjalizacyjnego dla użytkowników, stworzyliśmy straszne naruszenie hermetyzacji.
Przykład teoretyczny:
Klasa Foo ma 4 metody i potrzebuje do inicjalizacji liczby całkowitej, więc jej konstruktor wygląda jak Foo (rozmiar int) i od razu jest jasne dla użytkowników klasy Foo , że muszą podać rozmiar w instancji, aby Foo działało.
Powiedzmy, że ta konkretna implementacja Foo może również potrzebować widgetu Widget do wykonania swojej pracy. Wstrzyknięcie konstruktora tej zależności spowodowałoby utworzenie konstruktora takiego jak Foo (rozmiar int, widżet IWidget)
Irytuje mnie to, że mamy teraz konstruktor, który miesza dane inicjalizacyjne z zależnościami - jedno wejście jest interesujące dla użytkownika klasy ( rozmiar ), drugie jest wewnętrzną zależnością, która służy tylko zmyleniu użytkownika i jest implementacją szczegół ( widżet ).
Parametr size NIE jest zależnością - to po prostu wartość inicjująca dla instancji. IoC jest dobre dla zależności zewnętrznych (jak widget), ale nie dla inicjalizacji stanu wewnętrznego.
Co gorsza, co jeśli Widget jest potrzebny tylko dla 2 z 4 metod tej klasy; Mogę ponosić narzut na tworzenie instancji dla Widget, nawet jeśli nie może być używany!
Jak to skompromitować / pogodzić?
Jedną z metod jest przełączenie się wyłącznie na interfejsy w celu zdefiniowania umowy operacyjnej; i zaprzestanie używania konstruktorów przez użytkowników. Aby zachować spójność, dostęp do wszystkich obiektów musiałby być możliwy tylko za pośrednictwem interfejsów, a ich instancje byłyby tworzone tylko przez jakąś formę mechanizmu rozstrzygającego (np. Kontener IOC / DI). Tylko kontener może tworzyć instancje.
To rozwiązuje kwestię zależności Widget, ale jak zainicjować „rozmiar” bez uciekania się do oddzielnej metody inicjalizacji w interfejsie Foo? Korzystając z tego rozwiązania, straciliśmy możliwość zapewnienia pełnego zainicjowania instancji Foo przed jej uzyskaniem. Szkoda, bo bardzo podoba mi się pomysł i prostota wtrysku konstruktora.
Jak osiągnąć gwarantowaną inicjalizację w tym świecie DI, kiedy inicjalizacja to WIĘCEJ niż TYLKO zewnętrzne zależności?