Biorąc pod uwagę konstruktor, który nigdy nie będzie musiał używać różnych implementacji kilku obiektów, które inicjuje, czy nadal jest praktyczne stosowanie DI? W końcu nadal możemy chcieć przeprowadzić test jednostkowy.
Klasa, o której mowa, inicjuje kilka innych klas w swoim konstruktorze, a klasy, których używa, są dość specyficzne. Nigdy nie użyje innej implementacji. Czy mamy rację, unikając próby zaprogramowania interfejsu?
Odpowiedzi:
Zależy to od tego, czy masz pewność, że „nigdy, nigdy” nie jest poprawne (w czasie, gdy aplikacja będzie używana).
Ogólnie:
źródło
Chociaż przewaga kodowania na interfejsie jest dość oczywista, powinieneś zadać sobie pytanie, co dokładnie zyskasz, nie robiąc tego.
Następne pytanie brzmi: czy odpowiedzialność za wybór implementacji należy do klasy, czy nie? Może tak być lub nie i powinieneś działać odpowiednio.
Ostatecznie zawsze istnieje możliwość, że jakieś głupie ograniczenia wyjdą z nieba. Możesz uruchomić ten sam fragment kodu jednocześnie, a możliwość wprowadzenia implementacji może pomóc w synchronizacji. Lub po profilowaniu aplikacji możesz odkryć, że chcesz mieć inną strategię alokacji niż zwykłe tworzenie instancji. Albo pojawiają się problemy przekrojowe i nie masz pod ręką wsparcia AOP. Kto wie?
YAGNI sugeruje, że podczas pisania kodu ważne jest, aby nie dodawać nic zbędnego. Jedną z rzeczy, które programiści dodają do swojego kodu, nawet nie zdając sobie z tego sprawy, są niepotrzebne założenia. Na przykład „ta metoda może się przydać” lub „to się nigdy nie zmieni”. Oba dodają bałaganu do twojego projektu.
źródło
To zależy od różnych parametrów, ale oto kilka powodów, dla których nadal możesz chcieć używać DI:
Podsumowując: prawdopodobnie w takim przypadku możesz żyć bez DI, ale są szanse, że użycie DI skończy się na czystszym kodzie.
źródło
Kiedy projektujesz program lub funkcję, częścią procesu myślowego powinno być to, jak zamierzasz ją przetestować. Wstrzykiwanie zależności jest jednym z narzędzi testujących i powinno być traktowane jako część zestawu.
Dodatkowe zalety wstrzykiwania zależności i używania interfejsów zamiast klas są również korzystne, gdy aplikacja jest rozszerzana, ale można je również później łatwo i bezpiecznie zainstalować w kodzie źródłowym za pomocą funkcji wyszukiwania i zamiany. - nawet przy bardzo dużych projektach.
źródło
Wiele odpowiedzi na to pytanie można przedyskutować jako „możesz go potrzebować, ponieważ ...” jako YAGNI, jeśli nie chcesz robić nonszalancji.
Jeśli zastanawiasz się, jakie powody poza jednostkami wymagającymi programowania do interfejsu
Tak , zależne od iniekcji warto poza testem jednostkowym, jeśli potrzebujesz odwrócenia kontroli . Na przykład, jeśli implementacja jednego modułu wymaga innego modułu, który nie jest dostępny w jego warstwie.
Przykład: jeśli masz moduły
gui
=>businesslayer
=>driver
=>common
.W tym scenariuszu
businesslayer
można użyć,driver
aledriver
nie można użyćbusinesslayer
.Jeśli
driver
potrzebujesz funkcji wyższego poziomu, możesz zaimplementować tę funkcję, wbusinesslayer
której implementuje interfejs wcommon
warstwie.driver
wystarczy znać interfejs wcommon
warstwie.źródło
Tak, jesteś - po pierwsze, zapomnij o testowaniu jednostkowym jako przyczynie zaprojektowania kodu wokół narzędzi do testowania jednostkowego, nigdy nie jest dobrym pomysłem zginanie projektu kodu w celu dopasowania go do sztucznego ograniczenia. Jeśli twoje narzędzia zmuszają cię do tego, zdobądź lepsze narzędzia (np. Microsoft Fake / Moles, które pozwalają na wiele więcej opcji tworzenia fałszywych obiektów).
Na przykład, czy podzieliłbyś swoje klasy na tylko publiczne metody tylko dlatego, że narzędzia testowe nie działają z metodami prywatnymi? (Wiem, że panuje mądrość udawania, że nie trzeba testować prywatnych metod, ale czuję, że jest to reakcja na trudność w wykonaniu obecnych narzędzi, a nie prawdziwa reakcja na brak konieczności testowania prywatnych).,
W sumie sprowadza się to do tego, jakim jesteś TDDerem - „mockist”, jak to opisuje Fowler , musi zmienić kod, aby pasował do narzędzi, których używają, podczas gdy „klasyczni” testerzy tworzą testy, które są bardziej zintegrowane z naturą (tj. przetestuj klasę jako jednostkę, a nie każdą metodę), więc potrzeba interfejsów jest mniejsza, zwłaszcza jeśli używasz narzędzi, które mogą kpić z konkretnych klas.
źródło
Wstrzykiwanie zależności sprawia również, że wyraźniej jest, że obiekt HAS jest zależny.
Gdy ktoś inny użyje twojego obiektu naiwnie (bez patrzenia na konstruktor), przekona się, że będzie musiał skonfigurować usługi, połączenia itp. Nie było to oczywiste, ponieważ nie musiał przekazywać ich do konstruktora . Przekazywanie zależności sprawia, że jest bardziej zrozumiałe, co jest potrzebne.
Potencjalnie ukrywasz również fakt, że Twoje klasy mogą naruszać SRP. Jeśli przekazujesz wiele zależności (więcej niż 3), twoja klasa może robić zbyt wiele i powinna zostać zrefaktoryzowana. Ale jeśli tworzysz je w konstruktorze, ten zapach kodu zostanie ukryty.
źródło
Zgadzam się z oboma obozami tutaj i moim zdaniem sprawa jest nadal otwarta do debaty. YAGNI wymaga, abym nie próbował zmieniać mojego kodu, aby pasował do przypuszczeń. Testowanie jednostkowe nie jest tutaj problemem, ponieważ mocno wierzę, że zależność nigdy się nie zmieni. Ale gdybym początkowo testował Jednostki, i tak nigdy bym tego nie osiągnął. Jakbym ostatecznie wśliznął się do DI.
Pozwól, że zaoferuję inną alternatywę dla mojego scenariusza
Dzięki wzorowi fabrycznemu mogę zlokalizować zależności w jednym miejscu. Podczas testowania mogę zmienić implementację w oparciu o kontekst i to wystarczy. Nie jest to sprzeczne z YAGNI ze względu na zalety abstrakcji kilku konstrukcji klasowych.
źródło