Poza strukturami wstrzykiwania zależności, wstrzykiwanie zależności (poprzez wstrzykiwanie konstruktora lub wstrzykiwanie settera) jest prawie grą o sumie zerowej: zmniejszasz sprzężenie między obiektem A i jego zależnością B, ale teraz każdy obiekt, który potrzebuje wystąpienia A, musi teraz również skonstruuj obiekt B.
Nieznacznie zmniejszyłeś sprzężenie między A i B, ale zmniejszyłeś hermetyzację A i zwiększyłeś sprzężenie między A i dowolną klasą, która musi zbudować instancję A, poprzez sprzężenie ich również z zależnościami A.
Zatem wstrzykiwanie zależności (bez frameworka) jest równie szkodliwe, jak pomocne.
Dodatkowy koszt jest często łatwo uzasadniony: jeśli kod klienta wie więcej o tym, jak zbudować zależność niż sam obiekt, to wstrzyknięcie zależności naprawdę zmniejsza sprzężenie; na przykład skaner nie wie dużo o tym, jak uzyskać lub skonstruować strumień wejściowy do analizy danych wejściowych, ani z jakiego źródła kod klienta chce analizować dane wejściowe, więc wstrzyknięcie konstruktora strumienia wejściowego jest oczywistym rozwiązaniem.
Testowanie jest kolejnym uzasadnieniem, aby móc użyć próbnych zależności. Powinno to oznaczać dodanie dodatkowego konstruktora używanego tylko do testowania, który pozwala wstrzykiwać zależności: jeśli zamiast tego zmienisz konstruktory tak, aby zawsze wymagały wstrzykiwania zależności, nagle musisz wiedzieć o zależnościach zależności w celu zbudowania swojej bezpośrednie zależności i nie można wykonać żadnej pracy.
Może to być pomocne, ale zdecydowanie powinieneś zadać sobie pytanie o każdą zależność, czy korzyść z testowania jest warta kosztu i czy naprawdę będę chciał kpić z tej zależności podczas testowania?
Po dodaniu struktury wstrzykiwania zależności, a konstrukcja zależności jest delegowana nie do kodu klienta, ale do struktury, analiza kosztów / korzyści zmienia się znacznie.
W ramach wstrzykiwania zależności kompromisy są nieco inne; to, co tracisz przez wstrzyknięcie zależności, to możliwość łatwego dowiedzenia się, na której implementacji się opierasz, i przeniesienie odpowiedzialności za podjęcie decyzji o zależności, na której polegasz, na proces automatycznego rozwiązywania problemów (np. jeśli potrzebujemy Foo @ Inject'ed , musi być coś, co @Provides Foo i którego wstrzyknięte zależności są dostępne), lub jakiś plik konfiguracyjny wysokiego poziomu, który określa, jakiego dostawcę należy użyć dla każdego zasobu, lub jakiejś hybrydy tych dwóch (na przykład może istnieć być zautomatyzowanym procesem rozwiązywania zależności, które w razie potrzeby można zastąpić za pomocą pliku konfiguracyjnego).
Podobnie jak w przypadku iniekcji konstruktora, myślę, że korzyść z tego jest znowu bardzo podobna do kosztu: nie musisz wiedzieć, kto dostarcza dane, na których polegasz, a jeśli istnieje wiele potencjalnych dostawców, nie musisz znać preferowanej kolejności sprawdzania dostawców, upewnij się, że każda lokalizacja, która potrzebuje kontroli danych dla wszystkich potencjalnych dostawców itp., ponieważ wszystko jest obsługiwane na wysokim poziomie przez wstrzyknięcie zależności Platforma.
Chociaż osobiście nie mam dużego doświadczenia z frameworkami DI, mam wrażenie, że zapewniają one więcej korzyści niż kosztów, gdy kłopot ze znalezieniem właściwego dostawcy potrzebnych danych lub usług jest wyższy niż ból głowy, gdy coś zawiedzie, nie wiedząc od razu, jaki kod dostarczył złe dane, co spowodowało późniejszą awarię kodu.
W niektórych przypadkach inne wzorce, które zaciemniają zależności (np. Lokalizatory usług), zostały już przyjęte (a być może także udowodniły swoją wartość), gdy na scenie pojawiły się frameworki DI, a frameworki DI zostały przyjęte, ponieważ oferowały pewną przewagę konkurencyjną, na przykład wymagały mniej kodu podstawowego lub potencjalnie robiąc mniej, aby ukryć dostawcę zależności, gdy konieczne będzie ustalenie, który dostawca faktycznie jest w użyciu.