Pytanie Co to jest wstrzyknięcie zależności?


Było już kilka pytań z konkretnymi pytaniami iniekcja zależności, na przykład kiedy go użyć i jakie są dla niego ramy. Jednak,

Co to jest zastrzyk uzależnienia i kiedy / dlaczego powinno, czy nie powinno być stosowane?


2635
2017-09-25 00:28


pochodzenie


Zobacz moją dyskusję na temat Dependency Injection Tutaj. - Kevin S.
Zgadzam się z komentarzami dotyczącymi linków. Rozumiem, że możesz chcieć nawiązać do kogoś innego. Ale przynajmniej dodaj, dlaczego je łączysz i co czyni ten link lepszym od innych linków, które mogłem uzyskać za pomocą Google - Christian Payne
@AR: Technicznie, Injection Depression jest nie specjalna forma IoC. Raczej IoC jest jedną z technik, która jest używana do zapewniania iniekcji Dependency. Inne techniki mogą być stosowane w celu dostarczenia Dependency Injection (chociaż IoC jest jedynym powszechnie używanym), a IoC jest również używany do wielu innych problemów. - Sean Reilly
Jeśli nie podsumujesz tego, nie wiemy, ile warte jest, aby go przeczytać i przeczytać - Casebash
Jeśli chodzi o linki, pamiętaj, że często znikają w ten czy inny sposób. W odpowiedziach na SO rośnie liczba martwych łączy. Tak więc, bez względu na to, jak dobry jest powiązany artykuł, nie jest wcale dobrze, jeśli nie możesz go znaleźć. - DOK


Odpowiedzi:


Zasadniczo, zamiast tworzyć obiekty zależne od obiektów lub zlecać im obiekt fabryczny, przekazujesz potrzebne zależności zewnętrznie, a ty stajesz się problemem dla kogoś innego. Ten "ktoś" jest albo obiektem znajdującym się dalej na wykresie zależności, albo wtryskiwaczem zależności (framework), który buduje wykres zależności. Zależność, ponieważ używam go tutaj, to jakikolwiek inny obiekt, do którego bieżący obiekt musi się odwoływać.

Jedną z głównych zalet zastrzyku zależności jest to, że może to ułatwić testowanie. Załóżmy, że masz obiekt, który w jego konstruktorze wykonuje coś takiego:

public SomeClass() {
    myObject = Factory.getObject();
}

Może to być kłopotliwe, gdy chcesz tylko uruchomić niektóre testy jednostkowe w SomeClass, szczególnie gdy myObject jest czymś, co zapewnia złożony dostęp do dysku lub sieci. Więc teraz patrzysz na szydercze myObject, ale także w jakiś sposób przechwytujesz połączenie fabryczne. Ciężko. Zamiast tego przekazuj obiekt jako argument do konstruktora. Teraz poruszyłeś problem w innym miejscu, ale testowanie może być znacznie łatwiejsze. Po prostu wykonaj dummy myObject i przekaż to. Konstruktor będzie teraz wyglądał trochę jak:

public SomeClass (MyClass myObject) {
    this.myObject = myObject;
}

Jest to jeden styl zastrzyku zależności - za pośrednictwem konstruktora. Możliwe są różne mechanizmy.

  • Jak zauważono w komentarzach, jedną z powszechnych alternatyw jest zdefiniowanie konstruktora typu "nic nie robić" i posiadanie zależności wstrzykiwanych za pomocą ustawiaczy właściwości (h / t @MikeVella).
  • Martin Fowler dokumentuje trzecią alternatywę (h / t @MarcDix), w której klasy jawnie implementują interfejs dla zależności, które chcą wstrzyknąć.

Gdy nie stosuje się iniekcji zależności (na przykład w klasach, które wykonują za dużo pracy w swoich konstruktorach itp.), Znacznie trudniej jest wyodrębnić komponenty podczas testowania jednostkowego.

W 2013 roku, kiedy pisałem tę odpowiedź, był to główny temat na Blog testowania Google. Jest to dla mnie największa zaleta, ponieważ nie zawsze potrzebna jest dodatkowa elastyczność w projektowaniu w czasie wykonywania (na przykład dla lokalizatora usług lub podobnych wzorów), ale często trzeba być w stanie odizolować klasy podczas testowania.


1638
2017-09-25 00:49



Przyznając, że Ben Hoffstein odwołuje się do artykułu Martina Fowlera jako wskazujący na "must-read" na ten temat, akceptuję odpowiedź wds, ponieważ w rzeczywistości odpowiada na to pytanie na SO. - AR.
+1 dla wyjaśnienia i motywacji: tworzenie obiektów, od których klasa zależy od czyjegoś problemu. Innym sposobem na stwierdzenie tego jest to, że DI czyni zajęcia bardziej spójnymi (mają mniej obowiązków). - Fuhrmanator
Mówisz, że zależność jest przekazywana "konstruktorowi", ale jak rozumiem, nie jest to ściśle prawdą. Jest to nadal iniekcja zależności, jeśli zależność jest ustawiona jako właściwość po utworzeniu obiektu, prawda? - Mike Vella
@MikeVella Tak, zgadza się. W większości przypadków nie ma to większego znaczenia, chociaż właściwości są zazwyczaj nieco bardziej elastyczne. Zmienię tekst nieco, by to zaznaczyć. - wds
Jedna z najlepszych odpowiedzi, jakie znalazłem do tej pory, dlatego jestem naprawdę zainteresowany jej poprawą. Brakuje opisu trzeciej formy wtrysku zależności: Wtrysk interfejsu. - Marc Dix


Najlepszą definicją, jaką dotąd odkryłem, jest jedno przez Jamesa Shore'a:

"Dependency Injection" to 25 USD   termin na 5-centową koncepcję. [...]   Wstrzykiwanie zależności oznacza dawanie   obiekt jego zmienne instancji. [...].

Jest artykuł Martina Fowlera to może się okazać przydatne.

Wstrzyknięcie zależne polega zasadniczo na dostarczaniu obiektów, których obiekt potrzebuje (zależności), zamiast samemu je konstruować. Jest to bardzo przydatna technika do testowania, ponieważ pozwala na wyśmiewanie się lub odrzucanie zależności.

Zależności można wstrzykiwać do obiektów za pomocą wielu środków (takich jak wstrzyknięcie konstruktora lub wstrzyknięcie ustawiające). Można nawet użyć specjalistycznych frameworków wtrysku zależności (na przykład Spring), ale na pewno nie są one wymagane. Nie potrzebujesz tych frameworków do zastrzyku zależności. Natychmiastowe tworzenie i przekazywanie obiektów (zależności) jest równie dobrym zastrzykiem, jak wstrzyknięcie przez strukturę.


2063
2017-09-26 16:50



Podoba mi się wyjaśnienie artykułu Jamesa, a zwłaszcza jego zakończenie: "Nadal musisz zadziwić się każdym podejściem, które ma trzy pojęcia (" TripPlanner "," CabAgency "i" AirlineAgency "), zamienia je w dziewięć klas plus, a następnie dodaje dziesiątki linii kodu kleju i konfiguracji XML zanim zostanie napisana jedna linia logiki aplikacji. " To jest to, co widziałem bardzo często (niestety) - ten zastrzyk zależności (który jest dobry jako taki, jak mu to wyjaśniono) jest nadużywany do nadmiernego komplikowania rzeczy, które mogłyby być łatwiejsze - kończąc pisanie "wspierającego" kodu ... - Matt
Odp: "Natychmiastowe tworzenie i przekazywanie obiektów (zależności) jest równie dobrym zastrzykiem, jak wstrzyknięcie przez framework.". Dlaczego ludzie robili to w frameworkach? - dzieciou
Z tego samego powodu, dla którego każda struktura ma (lub przynajmniej powinna być) napisana: ponieważ istnieje wiele powtarzających się / podstawowych kodów, które muszą być napisane, gdy osiągniesz pewną złożoność. Problem ten wiele razy ludzie sięgają po ramy, nawet jeśli nie jest to absolutnie potrzebne. - Thiago Arrais
To powinna być właściwa odpowiedź ... lub "Zależność od iniekcji" oznacza przekazanie referencji obiektu "" - Hal50000
Termin 25 USD na 5-centową koncepcję jest martwy. Oto dobry artykuł, który pomógł mi: codeproject.com/Articles/615139/... - Hill


Znalazłem ten zabawny przykład pod względem luźne powiązanie:

Każda aplikacja składa się z wielu obiektów, które współpracują ze sobą, aby wykonać kilka użytecznych rzeczy. Tradycyjnie każdy obiekt jest odpowiedzialny za uzyskanie własnych odniesień do zależnych obiektów (zależności), z którymi współpracuje. Prowadzi to do bardzo powiązanych klas i trudnego do testowania kodu.

Rozważmy na przykład a Car obiekt.

ZA Car zależy od kół, silnika, paliwa, akumulatora itd. Tradycyjnie definiujemy markę takich zależnych obiektów wraz z definicją Car obiekt.

Bez iniekcji zależnej (DI):

class Car{
  private Wheel wh = new NepaliRubberWheel();
  private Battery bt = new ExcideBattery();

  //The rest
}

Tutaj Car obiekt jest odpowiedzialny za tworzenie obiektów zależnych.

Co jeśli chcemy zmienić typ jego obiektu zależnego - powiedzmy Wheel - po wstępie NepaliRubberWheel() przebicia? Musimy odtworzyć obiekt Car z jego nową zależnością powiedzmy ChineseRubberWheel(), ale tylko Car producent może to zrobić.

Więc co robi Dependency Injection zrób to dla ...?

Podczas korzystania z iniekcji zależności obiekty mają swoje zależności w czasie wykonywania zamiast czasu kompilacji (czas produkcji samochodu). Abyśmy teraz mogli zmienić Wheel kiedy tylko chcemy. Tutaj dependency (wheel) mogą być wstrzykiwane do Car W czasie wykonywania.

Po użyciu wstrzyknięcia zależności:

Oto jesteśmy wstrzykiwanie  zależności (Koło i akumulator) w czasie pracy. Stąd termin: Injection Dependency. 

class Car{
  private Wheel wh = [Inject an Instance of Wheel (dependency of car) at runtime]
  private Battery bt = [Inject an Instance of Battery (dependency of car) at runtime]
  Car(Wheel wh,Battery bt) {
      this.wh = wh;
      this.bt = bt;
  }
  //Or we can have setters
  void setWheel(Wheel wh) {
      this.wh = wh;
  }
}

Źródło: Zrozumienie wtrysku zależności


507
2018-05-22 04:01



Sposób, w jaki to rozumiem, polega na tym, że zamiast tworzyć nowy obiekt jako część innego obiektu, możemy wstrzyknąć ten obiekt, kiedy i jeśli jest potrzebny, usuwając zależność pierwszego obiektu od niego. Czy to prawda? - JeliBeanMachine
Opisałem to na przykładzie kawiarni tutaj:digigene.com/design-patterns/dependency-injection-coffeeshop - Ali Nem
Naprawdę podoba mi się ta analogia, ponieważ jest po prostu angielska, posługując się prostą analogią. Powiedzmy, że jestem Toyotą, która wydała już zbyt dużo pieniędzy i energii, aby zrobić samochód od projektu do zwijania linii montażowej, jeśli istnieją renomowani producenci opon, dlaczego powinienem zacząć od zera, aby stworzyć dział produkcji opon, tj. new opona? Ja nie. Wszystko, co muszę zrobić, to kupić (wstrzyknąć za pośrednictwem paramu) z nich, zainstalować i wah-lah! Wracając do programowania, powiedzmy, że projekt C # musi używać istniejącej biblioteki / klasy, istnieją dwa sposoby uruchamiania / debugowania, 1-dodawanie odniesienia do całego projektu tego - Jeb50
(con't), .. zewnętrzna biblioteka / klasa, lub 2 - dodaj ją z biblioteki DLL. Dopóki nie będziemy musieli zobaczyć, co jest wewnątrz tej zewnętrznej klasy, dodanie jej jako DLL jest łatwiejszym sposobem. Więc opcja 1 to new to, opcja 2 jest przekazywana jako parametr. Może nie być dokładne, ale proste głupie łatwe do zrozumienia. - Jeb50
Cudowne wyjaśnienie, - Avan


Dependency Injection to praktyka, w której obiekty są projektowane w taki sposób, że otrzymują instancje obiektów z innych fragmentów kodu, zamiast konstruować je wewnętrznie. Oznacza to, że dowolny obiekt implementujący interfejs wymagany przez obiekt może zostać zastąpiony bez zmiany kodu, co upraszcza testowanie i poprawia oddzielenie.

Rozważmy na przykład następujące zdania:

public class PersonService {
  public void addManager( Person employee, Person newManager ) { ... }
  public void removeManager( Person employee, Person oldManager ) { ... }
  public Group getGroupByManager( Person manager ) { ... }
}

public class GroupMembershipService() {
  public void addPersonToGroup( Person person, Group group ) { ... }
  public void removePersonFromGroup( Person person, Group group ) { ... }
} 

W tym przykładzie implementacja PersonService::addManager i PersonService::removeManager potrzebowałby instancji GroupMembershipService, aby wykonać swoją pracę. Bez Injection Dependency tradycyjnym sposobem na zrobienie tego byłoby stworzenie nowego GroupMembershipService w konstruktorze PersonService i użyj tego atrybutu instancji w obu funkcjach. Jednakże, jeśli konstruktor GroupMembershipService ma wiele rzeczy, których wymaga, lub, co gorsza, jest kilka inicjatorów "ustawiających", które muszą być wywołane na GroupMembershipService, kod rośnie dość szybko, a PersonServiceteraz zależy nie tylko od GroupMembershipService ale także wszystko inne GroupMembershipService zależy od. Ponadto, powiązanie z GroupMembershipService jest zakodowany na stałe PersonService co oznacza, że ​​nie możesz "dummy up" a GroupMembershipService do testowania lub do użycia wzorca strategii w różnych częściach aplikacji.

Z Injection Dependency, zamiast tworzenia instancji GroupMembershipService w twoim PersonService, możesz przekazać to do PersonService konstruktor lub dodaj właściwość (program pobierający i ustawiający), aby ustawić lokalną instancję tego obiektu. Oznacza to, że twój PersonService nie musisz się już martwić o tworzenie GroupMembershipService, po prostu akceptuje te, które podano i pracuje z nimi. Oznacza to również, że wszystko, co jest podklasą GroupMembershipServicelub implementuje GroupMembershipService interfejs można "wstrzyknąć" do PersonServicei PersonService nie musi wiedzieć o zmianie.


233
2017-09-25 06:49



Byłoby wspaniale, gdyby można podać ten sam kod przykład po użyciu DI - CodyBugstein
Chciałbym, żeby Python miał coś takiego. Teraz musimy drwić z wszystkiego do testów. - user2601010
Możesz na pewno zrobić Zastrzyk zależności z Pythonem, ale wiele dużych bibliotek (Django, itp.) nie działa, ponieważ szydercze biblioteki w Pythonie są tak solidne. Nadal musisz pisać drwiny podczas korzystania z DI, to po prostu łatwiejsze. - Adam Ness


Przyjęta odpowiedź jest dobra - ale chciałbym dodać, że DI jest bardzo podobny do klasycznego unikania stałych w kodzie.

Gdy użyjesz jakiegoś stałego jak nazwa bazy danych, szybko przenieś ją z wnętrza kodu do pliku konfiguracyjnego i przekaż zmienną zawierającą tę wartość do miejsca, w którym jest potrzebna. Powodem tego jest to, że te stałe zwykle zmieniają się częściej niż reszta kodu. Na przykład, jeśli chcesz przetestować kod w testowej bazie danych.

DI jest analogiczne do tego w świecie programowania obiektowego. Wartości tam zamiast stałych literałów są całymi obiektami - ale powód przeniesienia kodu tworzącego je z kodu klasy jest podobny - obiekty zmieniają się częściej niż kod, który je wykorzystuje. Jednym z ważnych przypadków, w których taka zmiana jest potrzebna, są testy.


142
2018-01-06 18:33



+1 "obiekty zmieniają się częściej niż kod, który ich używa". Aby uogólnić, dodaj kierunek pośredni w punktach strumienia. W zależności od punktu strumienia, pośrednie są wywoływane przez różne nazwy! - Chethan
"bardzo przypomina klasyczne unikanie stałych w kodzie" - dsdsdsdsd


Wyobraźmy sobie, że chcesz łowić ryby:

  • Bez zastrzyku zależności musisz sam zająć się wszystkim. Musisz znaleźć łódź, kupić wędkę, poszukać przynęty itp. Jest to oczywiście możliwe, ale nakłada na ciebie dużą odpowiedzialność. Pod względem oprogramowania oznacza to, że musisz wykonać wyszukiwanie wszystkich tych rzeczy.

  • Z zastrzykiem uzależnienia, ktoś inny zajmie się wszystkimi przygotowaniami i udostępni ci potrzebny sprzęt. Otrzymasz ("wstrzykniesz") łódź, wędkę i przynętę - wszystko gotowe do użycia.


96
2017-10-22 04:47



Z drugiej strony, wyobraź sobie, że zatrudniłeś hydraulika do przerobienia łazienki, która następnie mówi: "Świetnie, oto lista narzędzi i materiałów, których potrzebuję, abyś dla mnie zyskał". Czy nie powinno to być zadanie hydraulika? - Josh Caswell
Aby ktoś musiał zatroszczyć się o jakąś osobę, o której nie ma pojęcia, ale nadal decyduje się zebrać listę łodzi, kij i przynętę - aczkolwiek jest gotowa do użycia. - Chookoos
@JoshCaswell Nie, to byłaby robota hydraulika. Jako klient musisz wykonać instalację hydrauliczną. Do tego potrzebny jest hydraulik. Hydraulik potrzebuje narzędzi. Aby je zdobyć, zostaje wyposażona przez firmę hydrauliczną. Jako klient nie chcesz dokładnie wiedzieć, co hydraulik robi lub potrzebuje. Jako hydraulik wiesz, czego potrzebujesz, ale chcesz tylko wykonywać swoją pracę, a nie wszystko. Jako pracodawca hydraulik jesteś odpowiedzialny za wyposażenie swoich hydraulików w to, czego potrzebują przed wysłaniem ich do domów ludzi. - kai
@kai Rozumiem twój punkt widzenia. W oprogramowaniu mówimy o fabryce, prawda? Ale DI zazwyczaj oznacza również, że klasa nie używa fabryki, ponieważ wciąż nie jest wstrzykiwana. Ty, klient, musiałbyś skontaktować się z pracodawcą (fabryką), aby dać ci narzędzia, abyś mógł przekazać je hydraulikowi. Czy nie tak to faktycznie działa w programie? Tak więc, podczas gdy klient (wywołując klasę / funkcję / cokolwiek) nie musi nabywać narzędzi, nadal musi być środkowym mężczyzną, aby zapewnić, że dotrze on do hydraulika (zastrzyk klasy) od pracodawcy (fabryki). - KingOfAllTrades
@KingOfAllTrades: Oczywiście w pewnym momencie musisz mieć kogoś zatrudniającego i wyposażającego hydraulików, albo nie masz hydraulików. Ale nie robisz tego klientowi. Klient po prostu prosi o hydraulika i otrzymuje już taki, który jest mu potrzebny do wykonania swojej pracy. W przypadku DI nadal masz jakiś kod do spełnienia zależności. Ale oddzielasz go od kodu, który wykonuje prawdziwą pracę. Jeśli weźmiesz go w najszerszym zakresie, twoje obiekty po prostu tworzą swoje zależności, a tworzenie obiektów-wykresów odbywa się na zewnątrz, często w kodzie init. - cHao


To jest najprostszym wyjaśnieniem Injection Dependency i Dependency Injection Container Jaki kiedykolwiek widziałem:

Bez iniekcji zależnej

  • Aplikacja wymaga Foo (np. Kontrolera), więc:
  • Aplikacja tworzy Foo
  • Aplikacja nazywa się Foo
    • Foo potrzebuje paska (np. Usługi), więc:
    • Foo tworzy pasek
    • Foo wzywa Bar
      • Bar potrzebuje Bima (usługa, repozytorium, …), więc:
      • Bar tworzy Bima
      • Bar coś robi

Z wtryskiem zależnym

  • Wymagania aplikacji Foo, która potrzebuje paska, który potrzebuje Bima, więc:
  • Aplikacja tworzy Bima
  • Aplikacja tworzy pasek i nadaje mu Bima
  • Aplikacja tworzy Foo i nadaje mu pasek
  • Aplikacja nazywa się Foo
    • Foo wzywa Bar
      • Bar coś robi

Korzystanie z pojemnika na wstrzyknięcia zależne

  • Aplikacja wymaga Foo, więc:
  • Aplikacja pobiera Foo z kontenera, więc:
    • Kontener tworzy Bima
    • Container tworzy Bar i nadaje mu Bima
    • Container tworzy Foo i nadaje mu Bar
  • Aplikacja nazywa się Foo
    • Foo wzywa Bar
      • Bar coś robi

Injection Dependency i zależności Kontenery wtryskowe są różne rzeczy:

  • Dependency Injection to metoda pisania lepszego kodu
  • Kontener DI to narzędzie pomagające w uzależnieniu od wstrzyknięć

Nie potrzebujesz pojemnika do wykonania iniekcji zależności. Jednak pojemnik może ci pomóc.


79
2018-05-05 11:53



@ Trix Czy dobrze jest użyć iniekcji zależności czy nie? - roottraveller
@rootTraveller google to twój przyjaciel: Kiedy nie należy używać wzoru iniekcji zależności? - Trix