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


3074

Zostało już opublikowanych kilka pytań z konkretnymi pytaniami dotyczącymi wstrzykiwania zależności , na przykład kiedy z niego korzystać i jakie są dostępne ramy. Jednak,

Co to jest zastrzyk zależności i kiedy / dlaczego należy go stosować lub nie?


Zobacz moją dyskusję na temat wstrzykiwania zależności tutaj .
Kevin S.,

33
Zgadzam się z komentarzami dotyczącymi linków. Rozumiem, że możesz odnieść się do kogoś innego. Ale przynajmniej dodaj, dlaczego je łączysz i co sprawia, że ​​ten link jest lepszy niż inne linki, które mogłem uzyskać za pomocą Google
Christian Payne

@AR: Technicznie, wstrzykiwanie zależności nie jest specjalną formą IoC. Przeciwnie, IoC jest jedną techniką stosowaną do zapewnienia wstrzykiwania zależności. Można zastosować inne techniki w celu zapewnienia Wstrzykiwania Zależności (chociaż IoC jest jedyną powszechnie używaną), a IoC jest również stosowany w wielu innych problemach.
Sean Reilly,

Jednym z najpiękniejszych wyjaśnień, jakie kiedykolwiek czytałem na temat DI, jest z Google Guice (wymawiane jako sok) http://code.google.com/p/google-guice/wiki/Motivation?tm=6
Raj

136
Jeśli chodzi o linki, pamiętaj, że często znikają w ten czy inny sposób. W odpowiedziach SO rośnie liczba martwych linków. Tak więc, bez względu na to, jak dobry jest linkowany artykuł, nie jest wcale dobry, jeśli nie możesz go znaleźć.
DOK

Odpowiedzi:


1931

Dependency Injection przekazuje zależność do innych obiektów lub frameworka (aplikator zależności).

Wstrzykiwanie zależności ułatwia testowanie. Wstrzyknięcie można wykonać za pomocą konstruktora .

SomeClass() ma następujący konstruktor:

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

Problem : W przypadku myObjectzłożonych zadań, takich jak dostęp do dysku lub dostęp do sieci, trudno jest przeprowadzić test jednostkowy SomeClass(). Programiści muszą kpić myObjecti mogą przechwycić połączenie fabryczne.

Alternatywne rozwiązanie :

  • Przekazywanie myObjectjako argument do konstruktora
public SomeClass (MyClass myObject) {
    this.myObject = myObject;
}

myObject można przekazać bezpośrednio, co ułatwia testowanie.

  • Jedną z powszechnych alternatyw jest zdefiniowanie konstruktora „nic nie rób” . Wstrzykiwanie zależności można wykonać za pomocą ustawiaczy. (h / t @MikeVella).
  • Martin Fowler dokumentuje trzecią alternatywę (h / t @MarcDix), w której klasy jawnie implementują interfejs dla zależności, które programiści chcieliby wprowadzić.

Trudniej jest izolować komponenty w testach jednostkowych bez wstrzykiwania zależności.

Kiedy w 2013 roku napisałem tę odpowiedź, był to główny temat na blogu testowym Google . Pozostaje to dla mnie największą zaletą, ponieważ programiści nie zawsze potrzebują dodatkowej elastyczności przy projektowaniu w czasie wykonywania (na przykład dla lokalizatora usług lub podobnych wzorców). Programiści często muszą izolować klasy podczas testowania.


25
Uznając, że odniesienie Bena Hoffsteina do artykułu Martina Fowlera jest konieczne, ponieważ wskazuje na „obowiązkową lekturę” na ten temat, akceptuję odpowiedź wds, ponieważ faktycznie odpowiada na pytanie tutaj na SO.
AR.

121
+1 za wyjaśnienie i motywację: tworzenie przedmiotów, od których klasa zależy od problemu innej osoby . Innym sposobem na powiedzenie jest to, że DI sprawia, że ​​klasy są bardziej spójne (mają mniej obowiązków).
Fuhrmanator

13
Mówisz, że zależność jest przekazywana „do konstruktora”, ale jak rozumiem, nie jest to do końca prawda. Nadal jest to wstrzykiwanie zależności, jeśli zależność jest ustawiana jako właściwość po utworzeniu wystąpienia obiektu, prawda?
Mike Vella,

1
@MikeVella Tak, to prawda. W większości przypadków nie robi to żadnej różnicy, chociaż właściwości są na ogół nieco bardziej elastyczne. Lekko zmodyfikuję tekst, aby to podkreślić.
wds

2
Jedna z najlepszych odpowiedzi, jakie do tej pory znalazłem, dlatego naprawdę jestem zainteresowany jej ulepszeniem. Brakuje opisu trzeciej formy wstrzykiwania zależności: wstrzykiwanie interfejsu .
Marc Dix

2351

Najlepsza definicja, jaką do tej pory znalazłem, to James Shore :

„Wstrzykiwanie zależności” to termin 25 dolarów za koncepcję 5 centów. [...] Wstrzykiwanie zależności oznacza nadanie obiektowi zmiennych instancji. [...]

Jest też artykuł Martina Fowlera, który może okazać się przydatny.

Wstrzykiwanie zależności polega w zasadzie na dostarczeniu obiektów, których potrzebuje obiekt (jego zależności), zamiast samemu je konstruować. Jest to bardzo przydatna technika testowania, ponieważ pozwala na kpienie lub eliminowanie zależności.

Zależności można wstrzykiwać do obiektów na wiele sposobów (takich jak wstrzykiwanie konstruktora lub wstrzykiwanie setera). W tym celu można nawet użyć specjalistycznych struktur wstrzykiwania zależności (np. Spring), ale z pewnością nie są one wymagane. Te frameworki nie są potrzebne do wstrzyknięcia zależności. Bezpośrednie tworzenie instancji i przekazywanie obiektów (zależności) jest tak samo dobre jak wstrzyknięcie jak wstrzyknięcie przez framework.


35
Podoba mi się wyjaśnienie artykułu Jamesa, a zwłaszcza jego końca: „Mimo to musisz podziwiać każde podejście, które wymaga trzech koncepcji („ TripPlanner ”,„ CabAgency ”i„ AirlineAgency ”), zamienia je w klasy ponad dziewięć, a następnie dodaje dziesiątki linii kodu kleju i konfiguracji XML, zanim zostanie napisany pojedynczy wiersz logiki aplikacji. ” To właśnie widziałem bardzo często (niestety) - ten zastrzyk zależności (co jest dobre samo w sobie, jak to wyjaśnił) jest niewłaściwie wykorzystywany do nadmiernej komplikacji rzeczy, które można było zrobić łatwiej - w końcu pisanie kodu „wspierającego” ...
Matt

2
Re: „Bezpośrednie tworzenie instancji i przekazywanie obiektów (zależności) jest tak samo dobre jak wstrzyknięcie jak wstrzyknięcie przez framework.”. Więc dlaczego ludzie stworzyli takie ramy?
dzieciou

13
Z tego samego powodu, dla którego każda frameworka (lub przynajmniej powinna) zostać napisana: ponieważ istnieje wiele powtarzających się / bojlerów kodu, które należy napisać po osiągnięciu określonej złożoności. Problem polega na tym, że ludzie sięgają po ramy, nawet jeśli nie są one absolutnie potrzebne.
Thiago Arrais,

14
Termin 25 dolarów na koncepcję 5 centów jest martwy. Oto dobry artykuł, który mi pomógł: codeproject.com/Articles/615139/…
Christine

@Matt Pliki konfiguracyjne to po prostu „Odroczenie decyzji” doprowadzone do skrajności - „Odłóż decyzję do faktycznego czasu wykonywania”. Sztylet, a zwłaszcza Sztylet, moim zdaniem znalazł słodki punkt „Odłóż decyzję do czasu montażu aplikacji”.
Thorbjørn Ravn Andersen

645

Znalazłem ten zabawny przykład w kategoriach luźnego sprzężenia :

Każda aplikacja składa się z wielu obiektów, które współpracują ze sobą w celu wykonania użytecznych czynności. Tradycyjnie każdy obiekt jest odpowiedzialny za uzyskanie własnych odniesień do obiektów zależnych (zależności), z którymi współpracuje. Prowadzi to do wysoce sprzężonych klas i trudnego do przetestowania kodu.

Na przykład rozważmy Car przedmiot.

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

Bez wtrysku zależności (DI):

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

  //The rest
}

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

Co jeśli chcemy zmienić typ obiektu zależnego - powiedzmy Wheel- po początkowych NepaliRubberWheel()nakłuciach? Musimy odtworzyć obiekt Car z jego nową zależnością ChineseRubberWheel(), ale tylko Carproducent może to zrobić.

Co zatem Dependency Injectiondla nas robi ...?

Podczas stosowania wstrzykiwania zależności obiekty otrzymują swoje zależności w czasie wykonywania, a nie w czasie kompilacji (czas produkcji samochodu) . Abyśmy mogli teraz zmieniać, Wheelkiedy tylko chcemy. Tutaj można wstrzyknąć dependency( wheel)Car w czasie wykonywania.

Po zastosowaniu wstrzyknięcia zależności:

Tutaj jesteśmy wstrzykiwanie z zależnościami (koło i akumulator) przy starcie. Stąd termin: wstrzyknięcie zależności.

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 wstrzykiwania zależności


20
Sposób, w jaki to rozumiem, polega na tym, że zamiast tworzenia nowego obiektu jako części innego obiektu, możemy wstrzyknąć ten obiekt, kiedy jest to konieczne, i tym samym usunąć 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,

11
Naprawdę podoba mi się ta analogia, ponieważ jest to zwykły angielski przy użyciu prostej analogii. Powiedzieć, że jestem Toyota, już spędził zbyt dużo finansowo i moc człowieka na co samochód od projektu do walcowania off montaż linii, jeśli istnieją istniejących producentów renomowanych opon, dlaczego powinienem zacząć od podstaw, aby dokonać podziału producenci opon czyli newdo opona? Ja nie. Wszystko, co muszę zrobić, to kupić od nich (wstrzyknąć przez param), zainstalować i wah-lah! Tak więc, wracając do programowania, powiedzmy, że projekt C # musi korzystać z istniejącej biblioteki / klasy, istnieją dwa sposoby uruchomienia / debugowania, 1-dodawanie odwołania do całego projektu
Jeb50

(con't), .. zewnętrzna biblioteka / klasa lub 2-dodaj ją z DLL. Chyba że musimy zobaczyć, co jest w tej klasie zewnętrznej, dodanie jej jako DLL jest łatwiejszym sposobem. Więc opcja 1 jest do newniego, opcja 2 przekazuje ją jako parametr. Może nie być dokładne, ale proste, głupie, łatwe do zrozumienia.
Jeb50,

1
@JeliBeanMachine (przepraszam za bardzo późną odpowiedź na komentarz ..) nie chodzi o to, że usuwamy zależność pierwszego obiektu od obiektu koła lub obiektu baterii, chodzi o to, że przekazujemy tę zależność, abyśmy mogli zmienić instancję lub implementację zależność. Przed: Samochód ma określoną zależność od NepaliRubberWheel. Po: Samochód ma wstrzykniętą zależność od instancji Koła.
Mikael Ohlson

263

Wstrzykiwanie zależności to praktyka polegająca na tym, że 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 każdy obiekt implementujący interfejs, który jest wymagany przez obiekt, można podstawić bez zmiany kodu, co upraszcza testowanie i poprawia odsprzęganie.

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

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 wdrożenie PersonService::addManageri PersonService::removeManagerpotrzebowałoby wystąpienia instancji GroupMembershipServicew celu wykonania swojej pracy. Bez wstrzykiwania zależności tradycyjnym sposobem wykonania tego byłoby utworzenie nowego elementu GroupMembershipServicew konstruktorze PersonServicei użycie tego atrybutu instancji w obu funkcjach. Jednakże, jeśli konstruktor GroupMembershipServicema wiele rzeczy, których wymaga, lub jeszcze gorzej, istnieją pewne „ustawiacze” inicjujące, które należy wywołać w GroupMembershipService, kod rośnie dość szybko, a PersonServiceteraz zależy nie tylko od, GroupMembershipServiceale i wszystkiego innego, co GroupMembershipServicezależy od. Co więcej, powiązanie z GroupMembershipServicejest zakodowane na stałe, PersonServiceco oznacza, że ​​nie można „zrobić manekina”GroupMembershipService do celów testowych lub do wykorzystania wzorca strategii w różnych częściach aplikacji.

Dzięki Dependency Injection zamiast tworzenia instancji GroupMembershipServicewewnątrz PersonService, możesz przekazać ją PersonServicekonstruktorowi lub dodać właściwość (moduł pobierający i ustawiający), aby ustawić jego lokalną instancję. Oznacza to, że PersonServicenie musisz się już martwić, jak utworzyć GroupMembershipService, akceptuje tylko te, które otrzymałeś i współpracuje z nimi. Oznacza to również, że wszystko, co jest podklasą GroupMembershipServicelub implementacją GroupMembershipServiceinterfejsu, może zostać „wstrzyknięte” do PersonServicei PersonServicenie musi wiedzieć o zmianie.


29
Byłoby świetnie, gdybyś mógł podać ten sam przykład kodu PO użyciu DI
CodyBugstein

170

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

Kiedy używasz stałej, np. Nazwy bazy danych, szybko przenosisz ją z wnętrza kodu do jakiegoś pliku konfiguracyjnego i przekazujesz 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 zamiast stałych literałów są całymi obiektami - ale powód przeniesienia tworzącego je kodu z kodu klasy jest podobny - obiekty zmieniają się częściej niż kod, który ich używa. Jednym z ważnych przypadków, w których taka zmiana jest potrzebna, są testy.


18
+1 „obiekty zmieniają się częściej niż kod, który ich używa”. Aby uogólnić, dodaj punkt pośredni w punktach strumienia. W zależności od punktu strumienia, kierunki nazywane są różnymi nazwami !!
Chethan

139

Spróbujmy prostego przykładu z klasami samochodów i silników , każdy samochód potrzebuje silnika, aby pojechać gdziekolwiek, przynajmniej na razie. Poniżej poniżej, jak będzie wyglądał kod bez wstrzykiwania zależności.

public class Car
{
    public Car()
    {
        GasEngine engine = new GasEngine();
        engine.Start();
    }
}

public class GasEngine
{
    public void Start()
    {
        Console.WriteLine("I use gas as my fuel!");
    }
}

Aby utworzyć instancję klasy Car, użyjemy następnego kodu:

Car car = new Car();

Problem z tym kodem, który ściśle powiązaliśmy z GasEngine i jeśli zdecydujemy się go zmienić na ElectricityEngine, będziemy musieli przepisać klasę samochodu. Im większa aplikacja, tym więcej problemów i bólu głowy będziemy musieli dodać i użyć nowego typu silnika.

Innymi słowy, przy takim podejściu nasza klasa wysokiego poziomu zależy od klasy GasEngine niższego poziomu, która narusza zasadę inwersji zależności (DIP) od SOLID. DIP sugeruje, że powinniśmy polegać na abstrakcjach, a nie na konkretnych klasach. Aby to spełnić, wprowadzamy interfejs IEngine i przepisujemy kod jak poniżej:

    public interface IEngine
    {
        void Start();
    }

    public class GasEngine : IEngine
    {
        public void Start()
        {
            Console.WriteLine("I use gas as my fuel!");
        }
    }

    public class ElectricityEngine : IEngine
    {
        public void Start()
        {
            Console.WriteLine("I am electrocar");
        }
    }

    public class Car
    {
        private readonly IEngine _engine;
        public Car(IEngine engine)
        {
            _engine = engine;
        }

        public void Run()
        {
            _engine.Start();
        }
    }

Teraz nasza klasa samochodów jest zależna tylko od interfejsu IEngine, a nie od konkretnej implementacji silnika. Teraz jedyną sztuczką jest to, jak stworzyć instancję samochodu i nadać jej konkretną konkretną klasę silnika, taką jak GasEngine lub ElectricityEngine. Tam właśnie wchodzi Dependency Injection .

   Car gasCar = new Car(new GasEngine());
   gasCar.Run();
   Car electroCar = new Car(new ElectricityEngine());
   electroCar.Run();

Tutaj w zasadzie wstrzykujemy (przekazujemy) naszą zależność (instancję silnika) do konstruktora Car. Więc teraz nasze klasy mają luźne sprzężenie między obiektami i ich zależnościami i możemy łatwo dodawać nowe typy silników bez zmiany klasy samochodu.

Główną zaletą wstrzykiwania zależności jest to, że klasy są luźniej sprzężone, ponieważ nie mają sztywnych zależności. Jest to zgodne z zasadą inwersji zależności, o której wspomniano powyżej. Zamiast odwoływać się do konkretnych implementacji, klasy żądają abstrakcji (zwykle interfejsów ), które są im dostarczane, kiedy klasa jest konstruowana.

Tak więc w końcu Wstrzykiwanie zależności jest tylko techniką osiągania luźnego sprzężenia między obiektami i ich zależnościami. Zamiast bezpośrednio tworzyć instancje zależności, których klasa potrzebuje do wykonania swoich działań, zależności są dostarczane do klasy (najczęściej) poprzez wstrzyknięcie konstruktora.

Również gdy mamy wiele zależności, bardzo dobrą praktyką jest używanie kontenerów Inversion of Control (IoC), dzięki którym możemy stwierdzić, które interfejsy powinny być mapowane na konkretne implementacje dla wszystkich naszych zależności, i możemy sprawić, aby te zależności zostały dla nas rozwiązane podczas konstruowania nasz przedmiot. Na przykład możemy określić w mapowaniu kontenera IoC, że zależność IEngine powinna być mapowana na klasę GasEngine, a kiedy poprosimy kontener IoC o instancję naszej klasy Car , automatycznie skonstruuje naszą klasę Car z zależnością GasEngine przeszedł.

AKTUALIZACJA: Niedawno obejrzałem kurs na temat EF Core autorstwa Julie Lerman, a także polubiłem jej krótką definicję dotyczącą DI.

Wstrzykiwanie zależności to wzorzec umożliwiający aplikacji wstrzykiwanie obiektów w locie do klas, które ich potrzebują, bez zmuszania tych klas do odpowiedzialności za te obiekty. Pozwala to na luźniejsze sprzężenie kodu, a Entity Framework Core podłącza się do tego samego systemu usług.


2
tylko z ciekawości, czym różni się to od strategii? Ten wzorzec obejmuje algorytmy i czyni je wymiennymi. Wygląda na to, że wzorce wstrzykiwania zależności i strategie są bardzo podobne.
eliksir

110

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

  • Bez zastrzyku uzależnienia musisz sam wszystko załatwić. Musisz znaleźć łódź, kupić wędkę, poszukać przynęty itp. Oczywiście jest to możliwe, ale wiąże się to z dużą odpowiedzialnością. Pod względem oprogramowania oznacza to, że musisz wykonać wyszukiwanie wszystkich tych rzeczy.

  • Dzięki wstrzyknięciu zależności ktoś zajmuje się całym przygotowaniem i udostępnia wymagane wyposażenie. Otrzymasz („zastrzyk”) łódź, wędkę i przynętę - wszystko gotowe do użycia.


59
Drugą stroną jest, wyobraź sobie, że wynajmujesz hydraulika, aby przerobić łazienkę, a następnie mówi: „Świetnie, oto lista narzędzi i materiałów, które musisz dla mnie zdobyć”. Czy to nie powinna być praca hydraulika?
jscs

Aby ktoś musiał zająć się kimś, o czym nie ma pojęcia, ale nadal decyduje się na zebranie listy łodzi, kija i przynęty - aczkolwiek gotowych do użycia.
Chookoos,

22
@JoshCaswell Nie, to zadanie dla hydraulika. Jako klient potrzebujesz wykonanej instalacji hydraulicznej. Do tego potrzebujesz hydraulika. Hydraulik potrzebuje swoich narzędzi. Aby je zdobyć, zostaje wyposażony przez firmę wodno-kanalizacyjną. Jako klient nie chcesz dokładnie wiedzieć, co robi hydraulik lub czego potrzebuje. Jako hydraulik wiesz, czego potrzebujesz, ale po prostu chcesz wykonywać swoją pracę, a nie wszystko. Jako pracodawca hydraulika jesteś odpowiedzialny za wyposażenie swoich hydraulików w to, czego potrzebują przed wysłaniem ich do domów ludzi.
sara,

@ kai Rozumiem twój punkt widzenia. W oprogramowaniu mówimy o fabryce, prawda? Ale DI zwykle oznacza również, że klasa nie korzysta z fabryki, ponieważ nadal nie jest ona wstrzykiwana. Ty, klient, musisz skontaktować się z pracodawcą (fabryką), aby dostarczyć narzędzia, abyś mógł przejść do hydraulika. Czy tak nie byłoby tak naprawdę w programie? Tak więc, chociaż klient (wywołujący klasę / funkcję / cokolwiek) nie musi zamawiać narzędzi, nadal musi być pośrednikiem, który dopilnuje, aby dotarł do hydraulika (klasa wstrzyknięta) od pracodawcy (fabryki).
KingOfAllTrades

1
@KingOfAllTrades: Oczywiście w pewnym momencie musisz zatrudnić i wyposażyć hydraulików lub nie masz hydraulików. Ale nie robisz tego klient. Klient prosi tylko o hydraulika, a ten jest już wyposażony w to, czego potrzebuje, aby wykonywać swoją pracę. Dzięki DI wciąż masz trochę kodu, który spełnia zależności. Ale oddzielasz go od kodu, który naprawdę działa. Jeśli weźmiesz to w pełnym zakresie, twoje obiekty po prostu ujawnią swoje zależności, a budowanie wykresów obiektowych odbywa się na zewnątrz, często w kodzie init.
cHao

102

To jest najprostsze wyjaśnienie dotyczące wstrzykiwania zależności i kontenera wstrzykiwania zależności , jakie kiedykolwiek widziałem:

Bez wstrzykiwania zależności

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

Z wtryskiem zależnym

  • Aplikacja potrzebuje Foo, która potrzebuje paska, który potrzebuje Bim, więc:
  • Aplikacja tworzy Bim
  • Aplikacja tworzy Bar i nadaje mu Bim
  • Aplikacja tworzy Foo i daje mu pasek
  • Aplikacja wywołuje Foo
    • Foo nazywa się Bar
      • Bar coś robi

Korzystanie z pojemnika do wstrzykiwań zależności

  • Aplikacja wymaga Foo, więc:
  • Aplikacja pobiera Foo z kontenera, więc:
    • Kontener tworzy Bim
    • Kontener tworzy pasek i nadaje mu bim
    • Kontener tworzy Foo i daje mu Bar
  • Aplikacja wywołuje Foo
    • Foo nazywa się Bar
      • Bar coś robi

Wstrzykiwanie zależności i zależność Pojemniki do wstrzykiwań są różne:

  • Dependency Injection to metoda pisania lepszego kodu
  • DI Container to narzędzie, które pomaga wstrzykiwać zależności

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



55

Czy „wstrzykiwanie zależności” nie oznacza po prostu używania sparametryzowanych konstruktorów i ustawiaczy publicznych?

Artykuł Jamesa Shore'a pokazuje następujące przykłady do porównania .

Konstruktor bez wstrzykiwania zależności:

public class Example { 
  private DatabaseThingie myDatabase; 

  public Example() { 
    myDatabase = new DatabaseThingie(); 
  } 

  public void doStuff() { 
    ... 
    myDatabase.getData(); 
    ... 
  } 
} 

Konstruktor z wtryskiem zależności:

public class Example { 
  private DatabaseThingie myDatabase; 

  public Example(DatabaseThingie useThisDatabaseInstead) { 
    myDatabase = useThisDatabaseInstead; 
  }

  public void doStuff() { 
    ... 
    myDatabase.getData(); 
    ... 
  } 
}

Z pewnością w wersji DI nie chcesz inicjalizować obiektu myDatabase w konstruktorze bez argumentów? Wydaje się, że nie ma sensu i służyłby do rzucenia wyjątku, gdybyś próbował wywołać DoStuff bez wywoływania przeciążonego konstruktora?
Matt Wilko

Tylko jeśli new DatabaseThingie()nie wygeneruje prawidłowej instancji myDatabase.
JaneGoodall

40

Aby uczynić koncepcję wtrysku zależnego prostą do zrozumienia. Weźmy przykład przycisku przełącznika do przełączania (włączania / wyłączania) żarówki.

Bez wstrzykiwania zależności

Switch musi wcześniej wiedzieć, do której żarówki jestem podłączony (zależność na stałe). Więc,

Przełącznik -> Przełącznik PermanentBulb // jest bezpośrednio podłączony do stałej żarówki, testowanie nie jest łatwe

Switch(){
PermanentBulb = new Bulb();
PermanentBulb.Toggle();
}

Z wtryskiem zależnym

Switch wie tylko, że muszę włączyć / wyłączyć cokolwiek, co zostanie mi przekazane. Więc,

Przełącznik -> Żarówka 1 LUB Żarówka 2 LUB NightBulb (zależność wstrzyknięta)

Switch(AnyBulb){ //pass it whichever bulb you like
AnyBulb.Toggle();
}

Modyfikacja Jamesa dla przełącznika i żarówki:

public class SwitchTest { 
  TestToggleBulb() { 
    MockBulb mockbulb = new MockBulb(); 

    // MockBulb is a subclass of Bulb, so we can 
    // "inject" it here: 
    Switch switch = new Switch(mockBulb); 

    switch.ToggleBulb(); 
    mockBulb.AssertToggleWasCalled(); 
  } 
}

public class Switch { 
  private Bulb myBulb; 

  public Switch() { 
    myBulb = new Bulb(); 
  } 

  public Switch(Bulb useThisBulbInstead) { 
    myBulb = useThisBulbInstead; 
  } 

  public void ToggleBulb() { 
    ... 
    myBulb.Toggle(); 
    ... 
  } 
}`

36

Co to jest wstrzykiwanie zależności (DI)?

Jak powiedzieli inni, Dependency Injection (DI) usuwa odpowiedzialność za bezpośrednie tworzenie i zarządzanie długością życia, innych obiektów obiektowych, od których zależy nasza klasa zainteresowań (klasa konsumentów) (w sensie UML ). Te instancje są zamiast tego przekazywane do naszej klasy konsumenta, zwykle jako parametry konstruktora lub za pomocą ustawiaczy właściwości (zarządzanie instancją obiektu zależności i przekazywaniem do klasy konsumenta jest zwykle wykonywane przez kontener Inversion of Control (IoC) , ale to inny temat) .

DI, DIP i SOLID

W szczególności, w paradygmacie Roberta C Martina SOLID zasad Object Oriented projekt , DIjest jednym z możliwych implementacji Dependency Inversion Principle (DIP) . DIP jest Dz SOLIDmantrą - inne implementacje DIP obejmują lokalizatora usług i wzorców wtyczki.

Celem DIP jest oddzielenie szczelne, betonowe zależności między klasami, a zamiast tego, aby poluzować sprzęgło za pomocą abstrakcji, co można osiągnąć poprzez interface, abstract classlub pure virtual class, w zależności od języka i podejścia stosowanego.

Bez DIP nasz kod (nazwałam tę „klasą konsumpcyjną”) jest bezpośrednio połączony z konkretną zależnością, a także często jest obciążony odpowiedzialnością za uzyskanie i zarządzanie instancją tej zależności, tj. Koncepcyjnie:

"I need to create/use a Foo and invoke method `GetBar()`"

Podczas gdy po zastosowaniu DIP wymóg został rozluźniony, a problem uzyskiwania i zarządzania Fooczasem trwania zależności został usunięty:

"I need to invoke something which offers `GetBar()`"

Dlaczego warto korzystać z DIP (i DI)?

Oddzielenie zależności między klasami w ten sposób pozwala na łatwe zastąpienie tych klas zależności innymi implementacjami, które również spełniają warunki abstrakcji (np. Zależność można przełączać za pomocą innej implementacji tego samego interfejsu). Ponadto, jak wspominają inni, ewentualnie Najczęstszym powodem do klas oddzielić poprzez DIP jest umożliwienie spożywania klasy należy badać w izolacji, ponieważ te same zależności mogą być teraz zgaszone i / lub wyśmiewany.

Jedną z konsekwencji DI jest to, że zarządzanie żywotnością instancji obiektów zależności nie jest już kontrolowane przez konsumującą klasę, ponieważ obiekt zależności jest teraz przekazywany do konsumującej klasy (poprzez wstrzyknięcie konstruktora lub ustawiacza).

Można to zobaczyć na różne sposoby:

  • Jeśli zachowana musi zostać kontrola zależności przez klasę konsumpcji przez całe życie, kontrolę można przywrócić poprzez wstrzyknięcie (abstrakcyjnej) fabryki do tworzenia instancji klasy zależności do klasy konsumenta. Konsument będzie mógł uzyskać instancje Createw fabryce w razie potrzeby i zlikwidować je po zakończeniu.
  • Lub kontrolę życia instancji zależności można zrezygnować z kontenera IoC (więcej na ten temat poniżej).

Kiedy stosować DI?

  • Tam, gdzie prawdopodobnie zajdzie potrzeba zastąpienia zależności równoważnym wdrożeniem,
  • Za każdym razem, gdy będziesz musiał przetestować metody klasy w oderwaniu od jej zależności,
  • Gdzie niepewność okresu istnienia zależności może uzasadniać eksperymenty (np. Hej, MyDepClassczy wątek jest bezpieczny - co, jeśli zrobimy z niego singleton i wstrzykniemy ten sam przypadek wszystkim konsumentom?)

Przykład

Oto prosta implementacja w języku C #. Biorąc pod uwagę poniższą klasę konsumpcyjną:

public class MyLogger
{
   public void LogRecord(string somethingToLog)
   {
      Console.WriteLine("{0:HH:mm:ss} - {1}", DateTime.Now, somethingToLog);
   }
}

Choć z pozoru nieszkodliwy, ma dwie staticzależności od dwóch innych klas System.DateTimei System.Console, co nie tylko ogranicza opcje wyjściowe rejestrowania (logowanie do konsoli będzie bezwartościowe, jeśli nikt nie patrzy), ale co gorsza, trudno jest automatycznie przetestować, biorąc pod uwagę zależność od niedeterministyczny zegar systemowy.

Możemy jednak zastosować się DIPdo tej klasy, wyodrębniając obawę związaną z oznaczaniem czasu jako zależnością i łącząc MyLoggertylko z prostym interfejsem:

public interface IClock
{
    DateTime Now { get; }
}

Możemy również rozluźnić zależność od Consoleabstrakcji, takiej jak a TextWriter. Wstrzykiwanie zależności jest zwykle realizowane albo jako constructorwstrzyknięcie (przekazanie abstrakcji do zależności jako parametru do konstruktora klasy konsumującej) lub Setter Injection(przekazanie zależności przez setXyz()ustawiacz lub właściwość .Net ze {set;}zdefiniowaną). Preferowany jest Constructor Injection, ponieważ gwarantuje to, że klasa będzie w poprawnym stanie po zbudowaniu i pozwoli na oznaczenie wewnętrznych pól zależności jako readonly(C #) lub final(Java). Tak więc używając zastrzyku konstruktora w powyższym przykładzie, pozostawia nam to:

public class MyLogger : ILogger // Others will depend on our logger.
{
    private readonly TextWriter _output;
    private readonly IClock _clock;

    // Dependencies are injected through the constructor
    public MyLogger(TextWriter stream, IClock clock)
    {
        _output = stream;
        _clock = clock;
    }

    public void LogRecord(string somethingToLog)
    {
        // We can now use our dependencies through the abstraction 
        // and without knowledge of the lifespans of the dependencies
        _output.Write("{0:yyyy-MM-dd HH:mm:ss} - {1}", _clock.Now, somethingToLog);
    }
}

(Należy Clockpodać konkret, do którego można oczywiście wrócić DateTime.Now, a dwie zależności muszą być zapewnione przez kontener IoC poprzez wstrzyknięcie konstruktora)

Można zbudować automatyczny test jednostkowy, który ostatecznie dowodzi, że nasz rejestrator działa poprawnie, ponieważ teraz mamy kontrolę nad zależnościami - czasem i możemy szpiegować zapisywane dane wyjściowe:

[Test]
public void LoggingMustRecordAllInformationAndStampTheTime()
{
    // Arrange
    var mockClock = new Mock<IClock>();
    mockClock.Setup(c => c.Now).Returns(new DateTime(2015, 4, 11, 12, 31, 45));
    var fakeConsole = new StringWriter();

    // Act
    new MyLogger(fakeConsole, mockClock.Object)
        .LogRecord("Foo");

    // Assert
    Assert.AreEqual("2015-04-11 12:31:45 - Foo", fakeConsole.ToString());
}

Następne kroki

Wstrzykiwanie zależności jest niezmiennie związane z kontenerem Inwersji Kontroli (IoC) , aby wstrzykiwać (udostępniać) konkretne wystąpienia zależności i zarządzać instancjami długości życia. Podczas procesu konfiguracji / ładowania początkowego IoCkontenery umożliwiają zdefiniowanie następujących elementów:

  • mapowanie między każdą abstrakcją a skonfigurowaną konkretną implementacją (np. „za każdym razem, gdy konsument żąda IBar, zwraca ConcreteBarinstancję” )
  • można skonfigurować zasady zarządzania długością życia każdej zależności, np. w celu utworzenia nowego obiektu dla każdej instancji konsumenta, współużytkowania pojedynczej instancji zależności dla wszystkich konsumentów, udostępniania tej samej instancji zależności tylko w tym samym wątku itp.
  • W .Net kontenery IoC są świadome protokołów, takich jak IDisposablei przyjmują odpowiedzialność za Disposingzależności zgodnie ze skonfigurowanym zarządzaniem żywotnością.

Zazwyczaj po skonfigurowaniu / załadowaniu kontenerów IoC działają one płynnie w tle, umożliwiając koderowi skupienie się na dostępnym kodzie zamiast martwienia się o zależności.

Kluczem do kodu przyjaznego DI jest unikanie statycznego łączenia klas, a nie używanie new () do tworzenia zależności

Jak w powyższym przykładzie, odsprzężenie zależności wymaga pewnego wysiłku projektowego, a dla dewelopera konieczna jest zmiana paradygmatu, aby przełamać nawyk newbezpośredniego uzgadniania zależności i zamiast tego ufać kontenerowi w zarządzaniu zależnościami.

Ale korzyści jest wiele, zwłaszcza możliwość dokładnego przetestowania klasy zainteresowań.

Uwaga : Tworzenie / mapowanie / projekcja (via new ..()) POCO / POJO / Serialization DTOs / Entity Graphs / Anonymous JSON prognoz i in. - tj. Klasy lub rekordy „Tylko dane” - używane lub zwracane z metod nie są uważane za Zależności (w UML sense) i nie podlega DI. Używanie newdo wyświetlania jest w porządku.


1
Problemem jest DIP! = DI. DIP dotyczy oddzielania abstrakcji od implementacji: A. Moduły wysokiego poziomu nie powinny zależeć od modułów niskiego poziomu. Oba powinny zależeć od abstrakcji. B. Abstrakcje nie powinny zależeć od szczegółów. Szczegóły powinny zależeć od abstrakcji. DI to sposób na oddzielenie tworzenia obiektu od użycia obiektu.
Ricardo Rivaldo

Tak, rozróżnienie to zostało wyraźnie określone w moim paragrafie 2, „DI jedną z możliwych implementacji DIP” , w SOLIDNYM paradygmacie wuja Boba. Ja również to oczywiste we wcześniejszym poście.
StuartLC,

25

Cały sens Dependency Injection (DI) polega na utrzymaniu kodu źródłowego aplikacji w czystości i stabilności :

  • czysty kod inicjujący zależność
  • stabilny niezależnie od zastosowanej zależności

Praktycznie każdy wzorzec projektu oddziela obawy, aby przyszłe zmiany wpływały na minimalne pliki.

Specyficzną domeną DI jest delegowanie konfiguracji zależności i inicjalizacja.

Przykład: DI ze skryptem powłoki

Jeśli od czasu do czasu pracujesz poza Javą, przypomnij sobie, jak sourceczęsto jest używana w wielu językach skryptowych (Shell, Tcl itp., A nawet importw Pythonie niewłaściwie wykorzystywanych do tego celu).

Rozważ prosty dependent.shskrypt:

#!/bin/sh
# Dependent
touch         "one.txt" "two.txt"
archive_files "one.txt" "two.txt"

Skrypt jest zależny: nie zadziała samodzielnie ( archive_filesnie jest zdefiniowany).

Zdefiniować archive_filesw archive_files_zip.shskrypcie realizacji (używając zipw tym przypadku):

#!/bin/sh
# Dependency
function archive_files {
    zip files.zip "$@"
}

Zamiast source-ing skryptu implementacyjnego bezpośrednio w skrypcie zależnym, używasz injector.sh„kontenera”, który otacza oba „komponenty”:

#!/bin/sh 
# Injector
source ./archive_files_zip.sh
source ./dependent.sh

archive_files Zależność właśnie został wstrzyknięty do zależnego skryptu.

Mogłeś wstrzyknąć zależność, która implementuje archive_filesza pomocą tarlub xz.

Przykład: usunięcie DI

Gdyby dependent.shskrypt używał zależności bezpośrednio, podejście nazwano by wyszukiwaniem zależności (co jest odwrotne do wstrzykiwania zależności ):

#!/bin/sh
# Dependent

# dependency look-up
source ./archive_files_zip.sh

touch         "one.txt" "two.txt"
archive_files "one.txt" "two.txt"

Problem polega na tym, że zależny „komponent” musi sam dokonać inicjalizacji.

Kod źródłowy „komponentu” nie jest ani czysty, ani stabilny, ponieważ każda zmiana w inicjalizacji zależności wymaga również nowej wersji pliku kodu źródłowego „komponentów”.

Ostatnie słowa

DI nie jest tak mocno podkreślany i popularyzowany jak w frameworkach Java.

Ale jest to ogólne podejście do podzielenia obaw:

  • tworzenie aplikacji ( cykl życia wydania pojedynczego kodu źródłowego)
  • wdrożenie aplikacji ( wiele środowisk docelowych z niezależnymi cyklami życia)

Używanie konfiguracji tylko z wyszukiwaniem zależności nie pomaga, ponieważ liczba parametrów konfiguracyjnych może się zmieniać w zależności od zależności (np. Nowy typ uwierzytelnienia), a także liczba obsługiwanych typów zależności (np. Nowy typ bazy danych).


Dodałbym możliwość ukończenia określonej klasy (testowania) bez konieczności uzupełniania jej zależności, jako cel dla DI.
David

22

Wszystkie powyższe odpowiedzi są dobre, moim celem jest wyjaśnienie pojęcia w prosty sposób, aby każdy bez znajomości programowania mógł zrozumieć pojęcie

Wstrzykiwanie zależności jest jednym z wzorców projektowych, które pomagają nam tworzyć złożone systemy w prostszy sposób.

Widzimy szeroką gamę zastosowań tego wzoru w naszym codziennym życiu. Niektóre z przykładów to magnetofon, VCD, napęd CD itp.

Przenośny magnetofon szpulowy z połowy XX wieku.

Powyższe zdjęcie jest obrazem przenośnego magnetofonu szpulowego z połowy XX wieku. Źródło .

Podstawowym celem magnetofonu jest nagrywanie lub odtwarzanie dźwięku.

Podczas projektowania systemu wymaga szpuli do nagrywania lub odtwarzania dźwięku lub muzyki. Istnieją dwie możliwości zaprojektowania tego systemu

  1. możemy umieścić rolkę wewnątrz maszyny
  2. możemy zapewnić hak do kołowrotka, w którym można go umieścić.

Jeśli użyjemy pierwszego, musimy otworzyć maszynę, aby zmienić rolkę. jeśli zdecydujemy się na drugi, czyli zakładanie haka na rolkę, uzyskujemy dodatkową korzyść z grania dowolnej muzyki poprzez zmianę rolki. a także redukując funkcję tylko do grania na rolce.

Podobnie jak mądry wstrzykiwanie zależności jest procesem uzewnętrzniania zależności, aby skupić się tylko na konkretnej funkcjonalności komponentu, tak aby niezależne komponenty mogły być ze sobą łączone w celu utworzenia złożonego systemu.

Główne korzyści, które osiągnęliśmy dzięki zastosowaniu wstrzykiwania zależności.

  • Wysoka kohezja i luźne połączenie.
  • Uzewnętrznianie zależności i patrzenie tylko na odpowiedzialność.
  • Tworzenie elementów jako elementów i łączenie ich w duże systemy o wysokich możliwościach.
  • Pomaga opracowywać komponenty wysokiej jakości, ponieważ są one opracowywane niezależnie, są odpowiednio testowane.
  • Pomaga zastąpić komponent innym, jeśli jeden zawiedzie.

Teraz dni ta koncepcja stanowi podstawę dobrze znanych ram w świecie programowania. Spring Angular itp. To dobrze znane frameworki programowe zbudowane na szczycie tej koncepcji

Wstrzykiwanie zależności to wzorzec używany do tworzenia instancji obiektów, na których polegają inne obiekty bez wiedzy w czasie kompilacji, która klasa zostanie użyta do zapewnienia tej funkcjonalności lub po prostu sposób wstrzykiwania właściwości do obiektu nazywa się wstrzykiwaniem zależności.

Przykład wstrzyknięcia zależności

Wcześniej piszemy taki kod

Public MyClass{
 DependentClass dependentObject
 /*
  At somewhere in our code we need to instantiate 
  the object with new operator  inorder to use it or perform some method.
  */ 
  dependentObject= new DependentClass();
  dependentObject.someMethod();
}

W przypadku wstrzykiwania zależności wtryskiwacz zależności usunie dla nas instancję

Public MyClass{
 /* Dependency injector will instantiate object*/
 DependentClass dependentObject

 /*
  At somewhere in our code we perform some method. 
  The process of  instantiation will be handled by the dependency injector
 */ 

  dependentObject.someMethod();
}

Możesz także przeczytać

Różnica między inwersją kontroli i iniekcji zależności


17

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

Wstrzykiwanie zależności (DI) oznacza rozdzielanie obiektów, które są od siebie zależne. Powiedzmy, że obiekt A jest zależny od obiektu B, więc pomysł polega na oddzieleniu tych obiektów od siebie. Nie musimy na stałe kodować obiektu przy użyciu nowego słowa kluczowego, zamiast współdzielić zależności między obiektami w czasie wykonywania, pomimo czasu kompilacji. Jeśli o tym porozmawiamy

Jak działa wstrzykiwanie zależności na wiosnę:

Nie musimy na stałe kodować obiektu za pomocą nowego słowa kluczowego, a raczej zdefiniować zależność fasoli w pliku konfiguracyjnym. Kontener sprężynowy będzie odpowiedzialny za podłączenie wszystkich.

Inwersja kontroli (MKOl)

MKOl jest ogólną koncepcją i można ją wyrazić na wiele różnych sposobów, a wstrzykiwanie zależności jest jednym konkretnym przykładem MKOl.

Dwa rodzaje wstrzykiwania zależności:

  1. Wtrysk Konstruktora
  2. Zastrzyk setera

1. Zastrzyk zależny od konstruktora:

DI oparte na konstruktorze jest osiągane, gdy kontener wywołuje konstruktor klasy z wieloma argumentami, z których każdy reprezentuje zależność od innej klasy.

public class Triangle {

private String type;

public String getType(){
    return type;
 }

public Triangle(String type){   //constructor injection
    this.type=type;
 }
}
<bean id=triangle" class ="com.test.dependencyInjection.Triangle">
        <constructor-arg value="20"/>
  </bean>

2. Wstrzykiwanie zależności na bazie settera:

DI oparte na seterach jest osiągane przez kontener wywołujący metody setter dla twoich ziaren po wywołaniu konstruktora bez argumentu lub statycznej metody bez argumentu w celu utworzenia instancji komponentu bean.

public class Triangle{

 private String type;

 public String getType(){
    return type;
  }
 public void setType(String type){          //setter injection
    this.type = type;
  }
 }

<!-- setter injection -->
 <bean id="triangle" class="com.test.dependencyInjection.Triangle">
        <property name="type" value="equivialteral"/>

UWAGA: Dobrą zasadą jest stosowanie argumentów konstruktora dla obowiązkowych zależności, a ustawiaczy dla zależności opcjonalnych. Zauważ, że jeśli używamy adnotacji opartych na adnotacji @Required na seterach, można użyć ich do stworzenia seterów jako wymaganych zależności.


15

Najlepszą analogią, jaką mogę wymyślić, jest chirurg i jego asystent (asystenci) w sali operacyjnej, gdzie chirurg jest główną osobą i jego asystentem, który zapewnia różne elementy chirurgiczne, gdy tego potrzebuje, aby chirurg mógł skoncentrować się na jednym rzecz, którą robi najlepiej (operacja). Bez asystenta chirurg musi sam zdobyć komponenty za każdym razem, gdy tego potrzebuje.

Krótko mówiąc, DI jest techniką polegającą na usunięciu wspólnej dodatkowej odpowiedzialności (obciążenia) na komponentach za pobranie komponentów zależnych poprzez ich przekazanie.

DI przybliża cię do zasady pojedynczej odpowiedzialności (SR), takiej jak surgeon who can concentrate on surgery.

Kiedy stosować DI: Polecam używanie DI w prawie wszystkich projektach produkcyjnych (małych / dużych), szczególnie w ciągle zmieniających się środowiskach biznesowych :)

Powód: Ponieważ chcesz, aby Twój kod był łatwy do przetestowania, naśladowania itp., Abyś mógł szybko przetestować zmiany i wypchnąć go na rynek. Poza tym dlaczego nie miałbyś, skoro masz wiele niesamowitych darmowych narzędzi / ram, które wspierają cię w podróży do bazy kodu, w której masz większą kontrolę.


@WindRider Thanks. Nie mogę się więcej zgodzić. Ludzkie życie i ludzkie ciało są wspaniałymi przykładami doskonałości projektowej .. kręgosłup jest doskonałym przykładem ESB:) ...
Anwar Husain

15

Przykład, mamy 2 klasy Clienti Service. Clientbędzie użytyService

public class Service {
    public void doSomeThingInService() {
        // ...
    }
}

Bez wstrzykiwania zależności

Sposób 1)

public class Client {
    public void doSomeThingInClient() {
        Service service = new Service();
        service.doSomeThingInService();
    }
}

Sposób 2)

public class Client {
    Service service = new Service();
    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

Sposób 3)

public class Client {
    Service service;
    public Client() {
        service = new Service();
    }
    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

1) 2) 3) Korzystanie

Client client = new Client();
client.doSomeThingInService();

Zalety

  • Prosty

Niedogodności

  • Trudny do Clientklasy testowej
  • Kiedy zmieniamy Servicekonstruktor, musimy zmienić kod we wszystkich Serviceobiektach tworzenia obiektu

Użyj wstrzykiwania zależności

Sposób 1) Wstrzyknięcie konstruktora

public class Client {
    Service service;

    Client(Service service) {
        this.service = service;
    }

    // Example Client has 2 dependency 
    // Client(Service service, IDatabas database) {
    //    this.service = service;
    //    this.database = database;
    // }

    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

Za pomocą

Client client = new Client(new Service());
// Client client = new Client(new Service(), new SqliteDatabase());
client.doSomeThingInClient();

Sposób 2) Wstrzyknięcie setera

public class Client {
    Service service;

    public void setService(Service service) {
        this.service = service;
    }

    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

Za pomocą

Client client = new Client();
client.setService(new Service());
client.doSomeThingInClient();

Sposób 3) Wstrzyknięcie interfejsu

Czek https://en.wikipedia.org/wiki/Dependency_injection

===

Teraz ten kod jest już śledzony Dependency Injectioni jest łatwiej dla Clientklasy testowej .
Jednak nadal używamy new Service()wiele czasu i nie jest dobrze, gdy Servicekonstruktor zmiany jest zmienny. Aby temu zapobiec, możemy użyć wtryskiwacza DI, takiego jak
1) Prosta instrukcjaInjector

public class Injector {
    public static Service provideService(){
        return new Service();
    }

    public static IDatabase provideDatatBase(){
        return new SqliteDatabase();
    }
    public static ObjectA provideObjectA(){
        return new ObjectA(provideService(...));
    }
}

Za pomocą

Service service = Injector.provideService();

2) Użyj biblioteki: dla systemu Android sztylet2

Zalety

  • Ułatw test
  • Po zmianie Service należy go zmienić tylko w klasie Injector
  • Jeśli użyjesz use Constructor Injection, kiedy spojrzysz na konstruktor Client, zobaczysz ile zależności Clientklas

Niedogodności

  • Jeśli używasz use Constructor Injection, Serviceobiekt jest tworzony podczas Clienttworzenia, czasami używamy funkcji w Clientklasie bez użycia, Servicewięc utworzony Servicezostaje zmarnowany

Definicja wtrysku zależności

https://en.wikipedia.org/wiki/Dependency_injection

Zależność to obiekt, którego można użyć ( Service)
Wstrzyknięcie to przekazanie zależności ( Service) do obiektu zależnego ( Client), który by go użył


13

Oznacza to, że obiekty powinny mieć tyle zależności, ile jest potrzebne do wykonania ich zadania, a zależności powinny być nieliczne. Co więcej, zależności obiektu powinny dotyczyć interfejsów, a nie „konkretnych” obiektów, o ile to możliwe. (Konkretny obiekt to każdy obiekt utworzony za pomocą słowa kluczowego new.) Luźne sprzężenie zapewnia większą możliwość ponownego użycia, łatwiejszą konserwację i umożliwia łatwe dostarczanie „próbnych” obiektów zamiast kosztownych usług.

„Wstrzykiwanie zależności” (DI) jest również znane jako „Inwersja kontroli” (IoC), może być stosowane jako technika zachęcania do tego luźnego sprzężenia.

Istnieją dwa podstawowe podejścia do wdrażania DI:

  1. Wtrysk konstruktora
  2. Zastrzyk setera

Wtrysk konstruktora

Jest to technika przekazywania zależności między obiektami do konstruktora.

Zauważ, że konstruktor akceptuje interfejs, a nie konkretny obiekt. Należy również pamiętać, że wyjątek jest zgłaszany, jeśli parametr orderlayer ma wartość NULL. Podkreśla to znaczenie otrzymania prawidłowej zależności. Constructor Injection jest moim zdaniem preferowanym mechanizmem nadawania obiektowi swoich zależności. Podczas wywoływania obiektu jest jasne dla dewelopera, jakie zależności należy podać obiektowi „Osoba” w celu poprawnego wykonania.

Zastrzyk setera

Ale rozważ następujący przykład… Załóżmy, że masz klasę z dziesięcioma metodami, które nie mają zależności, ale dodajesz nową metodę, która ma zależność od IDAO. Możesz zmienić konstruktora, aby używał Constructor Injection, ale może to zmusić cię do zmiany wszystkich wywołań konstruktora w dowolnym miejscu. Alternatywnie, możesz po prostu dodać nowego konstruktora, który bierze zależność, ale wtedy skąd programista łatwo wie, kiedy użyć jednego konstruktora nad drugim. Wreszcie, jeśli tworzenie zależności jest bardzo kosztowne, dlaczego należy ją utworzyć i przekazać konstruktorowi, skoro może być używana rzadko? „Zastrzykiwanie setera” to kolejna technika DI, którą można zastosować w takich sytuacjach.

Zastrzyk Settera nie zmusza do przekazania zależności do konstruktora. Zamiast tego zależności są ustawiane na właściwości publiczne ujawniane przez obiekt w potrzebie. Jak sugerowano poprzednio, głównymi czynnikami motywującymi do tego są:

  1. Obsługa wstrzykiwania zależności bez konieczności modyfikowania konstruktora starszej klasy.
  2. Umożliwienie tworzenia kosztownych zasobów lub usług tak późno, jak to możliwe i tylko w razie potrzeby.

Oto przykład, jak wyglądałby powyższy kod:

public class Person {
    public Person() {}

    public IDAO Address {
        set { addressdao = value; }
        get {
            if (addressdao == null)
              throw new MemberAccessException("addressdao" +
                             " has not been initialized");
            return addressdao;
        }
    }

    public Address GetAddress() {
       // ... code that uses the addressdao object
       // to fetch address details from the datasource ...
    }

    // Should not be called directly;
    // use the public property instead
    private IDAO addressdao;

3
Myślę, że pierwszy akapit oddala się od pytania i wcale nie jest definicją DI (tj. Próbujesz zdefiniować SOLID, a nie DI). Technicznie, nawet jeśli masz 100 zależności, nadal możesz użyć wstrzykiwania zależności. Podobnie możliwe jest wstrzykiwanie konkretnych zależności - nadal jest to wstrzykiwanie zależności.
Jay Sullivan

10

Myślę, że skoro wszyscy pisali dla DI, zadam kilka pytań ...

  1. Jeśli masz konfigurację DI, w której wszystkie rzeczywiste implementacje (nie interfejsy), które zostaną wprowadzone do klasy (np. Usługi dla kontrolera), dlaczego nie jest to jakiś rodzaj twardego kodowania?
  2. Co jeśli chcę zmienić obiekt w czasie wykonywania? Na przykład moja konfiguracja już mówi, że kiedy tworzę instancję MyController, wstrzykiwam FileLogger jako ILogger. Ale mógłbym chcieć wprowadzić DatabaseLogger.
  3. Za każdym razem, gdy chcę zmienić obiekty, których potrzebuje moja AClass, muszę teraz patrzeć w dwa miejsca - samą klasę i plik konfiguracyjny. Jak to ułatwia życie?
  4. Jeśli Aproperty of AClass nie zostanie wstrzyknięty, czy trudniej go wyszydzić?
  5. Wracając do pierwszego pytania. Jeśli użycie nowego obiektu () jest złe, dlaczego wprowadzamy implementację, a nie interfejs? Myślę, że wielu z was mówi, że tak naprawdę wprowadzamy interfejs, ale konfiguracja powoduje, że określasz implementację tego interfejsu .. nie w czasie wykonywania .. jest on zakodowany na stałe podczas kompilacji.

Jest to oparte na opublikowanej odpowiedzi @Adam N.

Dlaczego PersonService nie musi się już martwić o GroupMembershipService? Wspomniałeś, że GroupMembership ma wiele rzeczy (obiektów / właściwości), od których zależy. Jeśli GMService był wymagany w PService, miałbyś go jako właściwość. Możesz wyśmiewać to, niezależnie od tego, czy wstrzyknąłeś go, czy nie. Jedynym momentem, w którym chciałbym, aby został wstrzyknięty, jest to, że GMService ma bardziej szczegółowe klasy potomne, których nie znasz do czasu uruchomienia. Następnie chcesz wstrzyknąć podklasę. Lub jeśli chcesz użyć tego jako singletonu lub prototypu. Szczerze mówiąc, plik konfiguracyjny ma wszystko zakodowane na stałe w zakresie podklasy dla typu (interfejsu), który zostanie wprowadzony podczas kompilacji.

EDYTOWAĆ

Miły komentarz Jose Maria Arranz na temat DI

DI zwiększa spójność poprzez usunięcie jakiejkolwiek potrzeby określenia kierunku zależności i napisania dowolnego kodu kleju.

Fałszywe. Kierunek zależności jest w formie XML lub jako adnotacje, a twoje zależności są zapisywane jako kod XML i adnotacje. XML i adnotacje SĄ kodem źródłowym.

DI zmniejsza sprzężenie, czyniąc wszystkie elementy modułowymi (tj. Wymiennymi) i ma dobrze zdefiniowane interfejsy.

Fałszywe. Nie potrzebujesz frameworka DI do zbudowania kodu modułowego opartego na interfejsach.

O wymiennych: dzięki bardzo prostemu archiwum .properties i Class.forName możesz zdefiniować, które klasy mogą być zmieniane. Jeśli JAKĄKOLWIEK klasę kodu można zmienić, Java nie jest dla Ciebie, użyj języka skryptowego. Nawiasem mówiąc: adnotacji nie można zmienić bez ponownej kompilacji.

Moim zdaniem istnieje jeden jedyny powód dla ram DI: redukcja płyty kotła. Dzięki dobrze wykonanemu systemowi fabrycznemu możesz zrobić to samo, bardziej kontrolowane i bardziej przewidywalne, jak preferowany framework DI, frameworki DI obiecują redukcję kodu (XML i adnotacje również są kodem źródłowym). Problem polega na tym, że redukcja płyty kotła jest po prostu realna w bardzo bardzo prostych przypadkach (jedna instancja na klasę i podobne), czasami w świecie rzeczywistym wybranie odpowiedniego obiektu usługi nie jest tak łatwe, jak odwzorowanie klasy na obiekt singletonu.


8

Popularne odpowiedzi są nieprzydatne, ponieważ definiują wstrzykiwanie zależności w sposób, który nie jest użyteczny. Zgódźmy się, że przez „zależność” rozumiemy jakiś wcześniejszy inny obiekt, którego potrzebuje nasz obiekt X. Ale nie mówimy, że robimy „zastrzyk zależności”, kiedy mówimy

$foo = Foo->new($bar);

Po prostu nazywamy to przekazywaniem parametrów do konstruktora. Robimy to regularnie od momentu wynalezienia konstruktorów.

„Wstrzykiwanie zależności” jest uważane za rodzaj „odwrócenia kontroli”, co oznacza, że ​​część logiki jest usuwana z dzwoniącego. Nie dzieje się tak, gdy wywołujący przekazuje parametry, więc jeśli byłyby to DI, DI nie oznaczałoby odwrócenia kontroli.

DI oznacza, że ​​istnieje poziom pośredni między dzwoniącym a konstruktorem, który zarządza zależnościami. Makefile to prosty przykład wstrzykiwania zależności. „Osoba dzwoniąca” to osoba wpisująca „make bar” w wierszu poleceń, a „konstruktor” to kompilator. Plik Makefile określa, że ​​pasek zależy od foo i robi to

gcc -c foo.cpp; gcc -c bar.cpp

przed zrobieniem

gcc foo.o bar.o -o bar

Osoba wpisująca „make bar” nie musi wiedzieć, że pasek zależy od foo. Wstrzyknięto zależność między „make bar” a gcc.

Głównym celem poziomu pośredniego jest nie tylko przekazywanie zależności do konstruktora, ale także lista wszystkich zależności w jednym miejscu i ukrycie ich przed koderem (nie zmuszanie kodera do ich dostarczenia).

Zwykle poziom pośredni zapewnia fabryki budowanych obiektów, które muszą spełniać rolę, którą musi spełniać każdy żądany typ obiektu. Jest tak, ponieważ mając poziom pośredni, który ukrywa szczegóły budowy, poniosłeś już karę abstrakcji nałożoną przez fabryki, więc równie dobrze możesz korzystać z fabryk.


8

Wstrzykiwanie zależności oznacza sposób (właściwie dowolny sposób ), aby jedna część kodu (np. Klasa) miała dostęp do zależności (innych części kodu, np. Innych klas, od których to zależy) w sposób modułowy, bez ich zakodowania (więc można je dowolnie zmieniać lub zastępować, a nawet w razie potrzeby ładować w innym czasie)

(i ps, tak, to stało się zbyt hiper-25-calową nazwą dla raczej prostej koncepcji) , moje .25centy


8

Wiem, że jest już wiele odpowiedzi, ale znalazłem to bardzo pomocne: http://tutorials.jenkov.com/dependency-injection/index.html

Bez zależności:

public class MyDao {

  protected DataSource dataSource = new DataSourceImpl(
    "driver", "url", "user", "password");

  //data access methods...
  public Person readPerson(int primaryKey) {...}     
}

Zależność:

public class MyDao {

  protected DataSource dataSource = null;

  public MyDao(String driver, String url, String user, String password) {
    this.dataSource = new DataSourceImpl(driver, url, user, password);
  }

  //data access methods...
  public Person readPerson(int primaryKey) {...}
}

Zauważ, jak DataSourceImplinstancja jest przenoszona do konstruktora. Konstruktor przyjmuje cztery parametry, które są czterema wartościami potrzebnymi przez DataSourceImpl. Chociaż MyDaoklasa nadal zależy od tych czterech wartości, sama nie spełnia już tych zależności. Są dostarczane przez dowolną klasę tworzącą MyDaoinstancję.


1
Czy DI nie przekazałby ci przez interfejs Twojego DataSourceImp już zbudowanego?
PmanAce

6

Wstrzykiwanie zależności jest jednym z możliwych rozwiązań, które można ogólnie nazwać wymogiem „zaciemniania zależności”. Obfuskacja zależności jest metodą usuwania „oczywistej” natury z procesu zapewniania zależności klasie, która tego wymaga, a zatem zaciemniania, w pewien sposób, udostępniania wspomnianej zależności tej klasie. To niekoniecznie jest zła rzecz. W rzeczywistości, zaciemniając sposób, w jaki zależność jest przekazywana do klasy, wówczas coś poza klasą jest odpowiedzialne za tworzenie zależności, co oznacza, że ​​w różnych scenariuszach inna implementacja zależności może być dostarczona do klasy bez wprowadzania żadnych zmian do klasy. Jest to doskonałe do przełączania między trybem produkcyjnym a testowym (np. Przy użyciu zależności „próbnej” usługi).

Niestety wadą jest to, że niektórzy ludzie założyli, że potrzebujesz specjalistycznego frameworka do zaciemniania zależności i że jesteś w jakiś sposób „mniejszym” programistą, jeśli zdecydujesz się nie używać do tego konkretnego frameworka. Kolejnym, niezwykle niepokojącym mitem, uważanym przez wielu, jest to, że zastrzyk uzależnienia jest jedynym sposobem na osiągnięcie zaciemnienia zależności. Jest to wyraźnie i historycznie i oczywiście w 100% błędne, ale będziesz miał trudności z przekonaniem niektórych osób, że istnieją alternatywy dla zastrzyku uzależnienia dla twoich wymagań zaciemniania zależności.

Programiści rozumieli wymóg zaciemniania zależności od lat i wiele alternatywnych rozwiązań ewoluowało zarówno przed, jak i po wymyśleniu zastrzyku zależności. Istnieją wzorce fabryczne, ale istnieje także wiele opcji wykorzystujących ThreadLocal, w których nie jest wymagane wstrzykiwanie do konkretnej instancji - zależność jest skutecznie wstrzykiwana do wątku, co ma tę zaletę, że udostępnia obiekt (za pomocą wygodnych metod statycznego pobierania) do dowolnegoklasa, która tego wymaga, bez konieczności dodawania adnotacji do klas, które tego wymagają, i skonfigurowania skomplikowanego „kleju” XML, aby tak się stało. Kiedy twoje zależności są wymagane do trwałości (JPA / JDO lub cokolwiek innego), pozwala to osiągnąć „tranaparent uporczywość” znacznie łatwiej i dzięki modelom domen i klasom modeli biznesowych złożonym wyłącznie z POJO (tj. Bez specyficznych ram / zablokowanych w adnotacjach).



5

Zanim przejdę do opisu technicznego, najpierw zwizualizuj go na przykładzie z życia, ponieważ znajdziesz wiele technicznych rzeczy do nauczenia się wstrzykiwania zależności, ale maksymalny czas, jaki ludzie tacy jak ja, nie mogą zrozumieć podstawowej koncepcji tego.

Na pierwszym zdjęciu Załóżmy, że masz fabrykę samochodów z wieloma jednostkami. Samochód jest faktycznie wbudowany w zespół montażowy, ale potrzebuje silnika , siedzeń oraz kół . Więc jednostki montażowej zależy od tych wszystkich jednostek i są Zależności fabryki.

Możesz czuć, że utrzymanie wszystkich zadań w tej fabryce jest zbyt skomplikowane, ponieważ wraz z głównym zadaniem (Montaż samochodu w zespole montażowym) musisz skupić się również na innych jednostkach . Utrzymanie jest teraz bardzo kosztowne, a budynek fabryki jest ogromny, więc możesz wziąć dodatkowe dolary do wynajęcia.

Teraz spójrz na drugie zdjęcie. Jeśli znajdziesz firmy oferujące tanie koła , siedzenia i silnik, które są tańsze niż koszty własnej produkcji, nie musisz robić ich w swojej fabryce. Możesz teraz wynająć mniejszy budynek tylko dla swojego zespołu montażowego, co zmniejszy zadanie konserwacji i zmniejszy dodatkowe koszty wynajmu. Teraz możesz skupić się tylko na głównym zadaniu (montaż samochodu).

Teraz możemy powiedzieć, że wszystkie zależności do montażu samochodu są wstrzykiwane fabrycznie od dostawców . Jest to przykład rzeczywistego wtrysku zależności (DI) .

Innymi słowy, wstrzykiwanie zależności jest techniką, w której jeden obiekt (lub metoda statyczna) dostarcza zależności drugiego obiektu. Tak więc przeniesienie zadania tworzenia obiektu na inną osobę i bezpośrednie użycie zależności nazywa się wstrzykiwaniem zależności.

To pomoże ci teraz nauczyć DI z jakimś słowem techy. To pokaże, kiedy używać DI, a kiedy nie .

Wszystko w jednej fabryce samochodów.

Prosta fabryka samochodów


1
najjaśniejsza odpowiedź spośród 40. Przykład i obrazy z życia. +1. Powinna być zaakceptowana odpowiedź.
Marche Remi

4

z książki Apress.Spring.Persistence.w.Hibernate.Oct.2010

Wstrzykiwanie zależności ma na celu oddzielenie pracy polegającej na usuwaniu zewnętrznych składników oprogramowania z logiki biznesowej aplikacji. Bez wstrzykiwania zależności szczegółowe informacje o tym, jak składnik uzyskuje dostęp do wymaganych usług, mogą zostać zakłócone przez kod tego składnika. Zwiększa to nie tylko ryzyko błędów, dodaje rozdęcie kodu i zwiększa złożoność konserwacji; łączy ściślej ze sobą komponenty, co utrudnia modyfikację zależności podczas refaktoryzacji lub testowania.


4

Dependency Injection (DI) to jeden z Design Patterns, który wykorzystuje podstawową cechę OOP - relację jednego obiektu z innym obiektem. Podczas gdy dziedziczenie dziedziczy jeden obiekt, aby wykonać bardziej złożony i specyficzny inny obiekt, relacja lub powiązanie po prostu tworzy wskaźnik do innego obiektu z jednego obiektu za pomocą atrybutu. Moc DI jest połączona z innymi funkcjami OOP, podobnie jak interfejsy i ukrywanie kodu. Załóżmy, że mamy w bibliotece klienta (subskrybenta), który dla uproszczenia może wypożyczyć tylko jedną książkę.

Interfejs książki:

package com.deepam.hidden;

public interface BookInterface {

public BookInterface setHeight(int height);
public BookInterface setPages(int pages);   
public int getHeight();
public int getPages();  

public String toString();
}

Następnie możemy mieć wiele rodzajów książek; jednym z nich jest fikcja:

package com.deepam.hidden;

public class FictionBook implements BookInterface {
int height = 0; // height in cm
int pages = 0; // number of pages

/** constructor */
public FictionBook() {
    // TODO Auto-generated constructor stub
}

@Override
public FictionBook setHeight(int height) {
  this.height = height;
  return this;
}

@Override
public FictionBook setPages(int pages) {
  this.pages = pages;
  return this;      
}

@Override
public int getHeight() {
    // TODO Auto-generated method stub
    return height;
}

@Override
public int getPages() {
    // TODO Auto-generated method stub
    return pages;
}

@Override
public String toString(){
    return ("height: " + height + ", " + "pages: " + pages);
}
}

Teraz subskrybent może mieć powiązanie z książką:

package com.deepam.hidden;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Subscriber {
BookInterface book;

/** constructor*/
public Subscriber() {
    // TODO Auto-generated constructor stub
}

// injection I
public void setBook(BookInterface book) {
    this.book = book;
}

// injection II
public BookInterface setBook(String bookName) {
    try {
        Class<?> cl = Class.forName(bookName);
        Constructor<?> constructor = cl.getConstructor(); // use it for parameters in constructor
        BookInterface book = (BookInterface) constructor.newInstance();
        //book = (BookInterface) Class.forName(bookName).newInstance();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
    return book;
}

public BookInterface getBook() {
  return book;
}

public static void main(String[] args) {

}

}

Wszystkie trzy klasy można ukryć dla własnej implementacji. Teraz możemy użyć tego kodu dla DI:

package com.deepam.implement;

import com.deepam.hidden.Subscriber;
import com.deepam.hidden.FictionBook;

public class CallHiddenImplBook {

public CallHiddenImplBook() {
    // TODO Auto-generated constructor stub
}

public void doIt() {
    Subscriber ab = new Subscriber();

    // injection I
    FictionBook bookI = new FictionBook();
    bookI.setHeight(30); // cm
    bookI.setPages(250);
    ab.setBook(bookI); // inject
    System.out.println("injection I " + ab.getBook().toString());

    // injection II
    FictionBook bookII = ((FictionBook) ab.setBook("com.deepam.hidden.FictionBook")).setHeight(5).setPages(108); // inject and set
    System.out.println("injection II " + ab.getBook().toString());      
}

public static void main(String[] args) {
    CallHiddenImplBook kh = new CallHiddenImplBook();
    kh.doIt();
}
}

Istnieje wiele różnych sposobów użycia wstrzykiwania zależności. Możliwe jest połączenie go z Singletonem itp., Ale nadal w podstawowym przypadku jest to tylko skojarzenie realizowane przez utworzenie atrybutu typu obiektu w innym obiekcie. Przydatność polega tylko i wyłącznie na tym, że ten kod, który powinniśmy pisać od nowa, jest zawsze dla nas przygotowany i wykonywany. Właśnie dlatego DI jest tak ściśle powiązany z Inversion of Control (IoC), co oznacza, że ​​nasz program przekazuje sterowanie innemu działającemu modułowi, który wykonuje wstrzykiwanie fasoli do naszego kodu. (Każdy obiekt, który można wstrzyknąć, może zostać podpisany lub uznany za Fasolę.) Na przykład wiosną robi się to poprzez utworzenie i inicjalizację ApplicationContextkontener, który działa dla nas. Po prostu w naszym kodzie tworzymy kontekst i wywołujemy inicjalizację ziaren. W tym momencie wstrzyknięcie zostało wykonane automatycznie.


4

Zastrzyk zależny dla 5-latków.

Kiedy idziesz i wyciągasz rzeczy z lodówki dla siebie, możesz powodować problemy. Możesz zostawić otwarte drzwi, możesz dostać coś, czego mama lub tata nie chcą, żebyś miał. Być może szukasz czegoś, czego nawet nie mamy lub które wygasło.

To, co powinieneś zrobić, to stwierdzenie potrzeby: „Potrzebuję czegoś do picia z lunchem”, a wtedy upewnimy się, że masz coś, kiedy usiądziesz i coś zjeść.


1
To jest wyraźnie odpowiedź rodzica. ;)
Marche Remi

4

Od Christoffera Noringa, książki Pablo Deelemana „Learning Angular - Second Edition”:

„Gdy nasze aplikacje rosną i ewoluują, każda z naszych jednostek kodu będzie wewnętrznie wymagać wystąpień innych obiektów , które w świecie inżynierii oprogramowania są lepiej znane jako zależności . Działanie polegające na przekazywaniu takich zależności do zależnego klienta jest znane jako wstrzykiwanie , i pociąga za sobą także udział innej jednostki kodowej o nazwie iniektor . Inżektor będzie odpowiedzialny za tworzenie instancji i ładowanie systemu wymaganych zależnościdzięki czemu są gotowe do użycia od momentu pomyślnego wstrzyknięcia do klienta. Jest to bardzo ważne, ponieważ klient nie wie nic o tym, jak utworzyć własną zależność i jest świadomy tylko interfejsu, który implementuje w celu ich użycia ”.

Od: Anton Moiseev. książka „Angular Development with Typescript, wydanie drugie”.:

„Krótko mówiąc, DI pomaga ci pisać kod w luźny sposób i sprawia, że kod jest bardziej testowalny i można go ponownie wykorzystać .”


3

W prostych słowach wstrzykiwanie zależności (DI) to sposób na usunięcie zależności lub ścisłe połączenie między różnymi obiektami. Wstrzykiwanie zależności zapewnia spójne zachowanie każdego obiektu.

DI to implementacja zasady MKOl wiosny, która mówi „Nie dzwoń do nas, my zadzwonimy”. Za pomocą programisty wstrzykiwania zależności nie trzeba tworzyć obiektu przy użyciu nowego słowa kluczowego.

Obiekty są raz ładowane do kontenera Spring, a następnie ponownie ich używamy, gdy tylko ich potrzebujemy, pobierając te obiekty z kontenera Spring przy użyciu metody getBean (String beanName).


3

Zastrzyk zależności jest sercem koncepcji związanej z Spring Framework. Podczas tworzenia szkieletu dowolnego projektu sprężyna może odgrywać istotną rolę, a tutaj zastrzyk zależności pojawia się w dzbanie.

W rzeczywistości załóżmy, że w java stworzyłeś dwie różne klasy, takie jak klasa A i klasa B, i niezależnie od funkcji dostępnej w klasie B, której chcesz użyć w klasie A, więc w tym czasie można zastosować wstrzykiwanie zależności. gdzie możesz utworzyć skrzynkę obiektu jednej klasy w drugiej, w ten sam sposób możesz wstrzyknąć całą klasę w inną klasę, aby była dostępna. w ten sposób można przezwyciężyć zależność.

WTRYSK ZALEŻNOŚCI JEST PO PROSTU SKLEJANIE DWÓCH KLAS I W TYM SAMYM CZASIE UTRZYMYWANIE JEGO ODDZIELNIE.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.