bez iniekcji zależnościedytuj

w poniższym przykładzie Javy Klasa Client zawiera zmienną członka usługi zainicjowaną przez konstruktor klienta. Klient kontroluje, które wdrożenie usługi jest wykorzystywane i kontroluje jej budowę. W tej sytuacji mówi się, że Klient ma twardo zakodowaną zależność od ExampleService.

// An example without dependency injectionpublic class Client { // Internal reference to the service used by this client private ExampleService service; // Constructor Client() { // Specify a specific implementation in the constructor instead of using dependency injection service = new ExampleService(); } // Method within this client that uses the services public String greet() { return "Hello " + service.getName(); }}

Dependency injection jest alternatywną techniką inicjalizacji zmiennej członkowskiej zamiast jawnego tworzenia obiektu usługowego, jak pokazano powyżej., Możemy dostosować ten przykład za pomocą różnych technik opisanych i zilustrowanych w podrozdziałach poniżej.

typy iniekcji zależnościedytuj

istnieją co najmniej trzy sposoby, w jakie obiekt klienta może otrzymać odniesienie do zewnętrznego modułu:

constructor iniection zależności są dostarczane przez konstruktor klasy klienta. Wtrysk settera klient wyświetla metodę settera, której wtryskiwacz używa do wtrysku zależności. interface injection interfejs zależności zapewnia metodę wtryskiwacza, która wstrzyknie zależność do dowolnego klienta przekazanego do niego., Klienci muszą zaimplementować interfejs, który wyświetla metodę settera akceptującą zależność.

Inne typyedytuj

możliwe jest, że diody mają inne typy wtrysku niż przedstawione powyżej.

frameworki testowe mogą również używać innych typów. Niektóre nowoczesne frameworki testowe nie wymagają nawet, aby klienci aktywnie akceptowali dependency injection, dzięki czemu legacy code może być testowany. W szczególności, w języku Java, możliwe jest użycie reflection do upublicznienia atrybutów prywatnych podczas testowania i tym samym akceptowanie iniekcji przez przypisanie.,

niektóre próby odwrócenia sterowania nie zapewniają całkowitego usunięcia zależności, ale zamiast tego po prostu zastępują jedną formę zależności inną. Z reguły, jeśli programista może spojrzeć tylko na kod klienta i powiedzieć, jaki framework jest używany, to klient ma twardo zakodowaną zależność od frameworku.

Konstruktor injectionEdit

metoda ta wymaga od klienta podania parametru w konstruktorze zależności.

Setter injectionEdit

ta metoda wymaga od klienta podania metody setter Dla zależności.,

Interface injectionEdit

jest to po prostu klient publikujący interfejs roli do metod settera zależności klienta. Może być użyty do ustalenia, w jaki sposób wtryskiwacz powinien rozmawiać z klientem podczas wstrzykiwania zależności.

// Service setter interface.public interface ServiceSetter { public void setService(Service service);}// Client classpublic class Client implements ServiceSetter { // Internal reference to the service used by this client. private Service service; // Set the service that this client is to use. @Override public void setService(Service service) { this.service = service; }}

Constructor injection comparisonEdit

preferowane, gdy wszystkie zależności mogą być skonstruowane jako pierwsze, ponieważ może być użyte do zapewnienia, że obiekt klienta jest zawsze w prawidłowym stanie, w przeciwieństwie do tego, aby niektóre odniesienia do zależności były null (nie być ustawione)., Jednak sama w sobie brakuje elastyczności, aby później zmienić swoje zależności. Może to być pierwszy krok w kierunku uczynienia klienta niezmiennym, a tym samym bezpiecznym dla wątku.

setter injection comparisonEdit

wymaga od klienta podania metody settera dla każdej zależności. Daje to swobodę manipulowania stanem odniesień do Zależności w dowolnym momencie. Zapewnia to elastyczność, ale jeśli ma być wstrzykiwana więcej niż jedna zależność, trudno jest Klientowi zapewnić, że wszystkie zależności zostaną wstrzyknięte, zanim klient będzie mógł zostać udostępniony do użytku.,

ponieważ te zastrzyki odbywają się niezależnie, nie ma sposobu, aby stwierdzić, kiedy wtryskiwacz jest gotowy okablowanie klienta. Zależność może zostać pozostawiona null po prostu przez wtryskiwacz, który nie wywoła swojego settera. Wymusza to sprawdzenie, czy wstrzyknięcie zostało zakończone od momentu złożenia klienta do momentu użycia.

Interface injection comparisonEdit

zaletą interfejsu injection jest to, że Zależności mogą być całkowicie nieświadome swoich klientów, ale nadal mogą otrzymać odniesienie do nowego klienta i, używając go, wysłać odniesienie do siebie z powrotem do klienta., W ten sposób zależności stają się wtryskiwaczami. Kluczem jest to, że metoda wstrzykiwania (która może być tylko klasyczną metodą settera)jest dostarczana przez interfejs.

do wprowadzenia klienta i jego zależności potrzebny jest jeszcze asembler. Asembler pobierze odniesienie do klienta, wrzuci je do interfejsu settera, który ustawia tę zależność i przekaże je do obiektu zależności, który zawróci i przekaże odniesienie do siebie z powrotem do klienta.,

aby interface injection miało wartość, zależność musi coś zrobić oprócz zwyczajnego przekazania odniesienia do siebie. Może to działać jako fabryczny lub pod-asembler w celu rozwiązania innych zależności, a tym samym abstrakcji niektórych szczegółów z głównego asemblera. Może to być zliczanie referencji, aby zależność wiedziała, ilu klientów z niej korzysta. Jeśli zależność utrzymuje kolekcję Klientów, może później wstrzyknąć je wszystkie z inną instancją.,

przykłady Asemblowaniaedit

ręczne asemblowanie w main ręcznie jest jednym ze sposobów implementacji dependency injection.

powyższy przykład ręcznie konstruuje Wykres obiektu, a następnie wywołuje go w jednym punkcie, aby rozpocząć jego działanie. Należy pamiętać, że ten wtryskiwacz nie jest czysty. Wykorzystuje jeden z obiektów, które konstruuje. Ma czysto konstrukcyjną relację z ExampleService, ale łączy konstrukcję z wykorzystaniem klienta. Nie powinno to być powszechne. Jest to jednak nieuniknione., Podobnie jak oprogramowanie obiektowe potrzebuje do uruchomienia nieobiektowej statycznej metody, takiej jak main (), tak Wykres obiektowy z iniekcją zależności potrzebuje co najmniej jednego (najlepiej tylko jednego) punktu wejścia, aby uruchomić całość.

Budowa Ręczna w głównej metodzie może nie być prosta i może obejmować wywoływanie budowniczych, fabryk lub innych wzorów budowlanych. Może to być dość zaawansowane i abstrakcyjne., Linia jest przekreślana z ręcznego wstrzykiwania zależności do framework dependency injection, gdy kod konstruujący nie jest już niestandardowy dla aplikacji, a zamiast tego uniwersalny.

frameworki takie jak Spring mogą konstruować te same obiekty i łączyć je ze sobą przed zwróceniem odniesienia do klienta. Wszystkie wzmianki o konkretnych przykładach można przenieść z kodu do danych konfiguracyjnych.

frameworki takie jak Spring pozwalają na eksternalizację szczegółów montażu w plikach konfiguracyjnych.Kod ten (powyżej) konstruuje obiekty i łączy je razem zgodnie z Beans.xml (poniżej)., ExampleService jest nadal skonstruowany, mimo że jest wymieniony tylko poniżej. W ten sposób można zdefiniować długi i złożony Wykres obiektów i jedyną klasą wymienioną w kodzie będzie ta z metodą punktu wejścia, którą w tym przypadku jest greet ().

w powyższym przykładzie klient i serwis nie musieli przechodzić żadnych zmian, aby zostały dostarczone do wiosny. Mogą pozostać prostymi Pojami. Pokazuje to, w jaki sposób Spring może łączyć usługi i klientów, którzy są całkowicie nieświadomi jej istnienia. Nie można tego powiedzieć, jeśli adnotacje wiosenne zostały dodane do klas., Dzięki temu, że adnotacje i wywołania specyficzne dla sprężyny są rozdzielane pomiędzy wiele klas, system pozostaje tylko luźno zależny od sprężyny. Może to być ważne, jeśli system zamierza przeżyć wiosnę.

wybór, aby zachować czyste POJOs nie przychodzi bez kosztów. Zamiast poświęcać wysiłek na tworzenie i utrzymywanie złożonych plików konfiguracyjnych, można po prostu użyć adnotacji do oznaczania klas i pozwolić Spring wykonać resztę pracy. Rozwiązywanie zależności może być proste, jeśli są zgodne z konwencją, taką jak dopasowanie według typu lub nazwy. Jest to wybór konwencji zamiast konfiguracji., Można również przypuszczać, że podczas refaktoryzacji do innego frameworka usunięcie adnotacji specyficznych dla frameworka byłoby trywialną częścią zadania, a wiele adnotacji iniekcyjnych jest teraz znormalizowanych.

@Componentpublic class ExampleService { public String getName() { return "World!"; }}

porównanie Montażówedytuj

różne implementacje wtryskiwaczy (fabryki, lokalizatory usług i kontenery wtrysku zależności) nie różnią się tak bardzo, jeśli chodzi o Wtrysk zależności. Różnica polega na tym, gdzie można je stosować., Przenieś wywołania do fabryki lub lokalizatora usług z klienta i do main i nagle main tworzy dość dobry kontener iniekcji zależności.

przenosząc całą wiedzę o wtryskiwaczu, czysty klient, wolny od wiedzy o świecie zewnętrznym, zostaje pozostawiony w tyle. Jednak każdy obiekt, który używa innych obiektów, może być uważany za klienta. Obiekt zawierający main nie jest wyjątkiem. Ten główny obiekt nie używa iniekcji zależności. W rzeczywistości używa wzorca lokalizatora usług. Nie można tego uniknąć, ponieważ wybór implementacji usług musi być dokonany gdzieś.,

Eksternalizacja zależności do plików konfiguracyjnych nie zmienia tego faktu. To, co sprawia, że ta rzeczywistość jest częścią dobrego projektu, to fakt, że lokalizator usług nie jest rozłożony na całej podstawie kodu. Jest on ograniczony do jednego miejsca na aplikację. Pozostawia to pozostałą część kodu wolną do używania dependency injection do tworzenia czystych klientów.

Dependency Injection PatternEdit

przykłady do tej pory były zbyt prostymi przykładami dotyczącymi konstruowania ciągu znaków., Jednak wzorzec wtrysku zależności jest najbardziej przydatny przy konstruowaniu wykresu obiektów, w którym obiekty komunikują się za pomocą komunikatów. Obiekty zbudowane w main będą trwać przez całe życie programu. Typowym wzorcem jest skonstruowanie wykresu, a następnie wywołanie jednej metody na jednym obiekcie, aby wysłać przepływ sterowania do wykresu obiektu. Podobnie jak main jest punktem wejścia do kodu statycznego, ta jedna metoda jest punktem wejścia do kodu niestatycznego aplikacji.,

przykład Angularjsedytuj

w strukturze AngularJS istnieją tylko trzy sposoby, w jakie komponent (obiekt lub funkcja) może uzyskać bezpośredni dostęp do swoich zależności:

  1. komponent może utworzyć zależność, zazwyczaj używając operatoranew.
  2. komponent może sprawdzić zależność, odwołując się do zmiennej globalnej.
  3. komponent może mieć zależność przekazaną do niego tam, gdzie jest potrzebna.

dwie pierwsze opcje tworzenia lub wyszukiwania zależności nie są optymalne, ponieważ kodują zależność od komponentu., Utrudnia to, jeśli nie jest niemożliwe, modyfikowanie zależności. Jest to szczególnie problematyczne w testach, gdzie często pożądane jest dostarczenie wzorcowych zależności do izolacji testu.

trzecia opcja jest najbardziej opłacalna, ponieważ usuwa odpowiedzialność za zlokalizowanie zależności od komponentu. Zależność jest po prostu przekazywana do komponentu.

w powyższym przykładzie SomeClass nie zajmuje się tworzeniem lub lokalizowaniem zależności greeter, jest po prostu przekazywana greeter, gdy jest tworzona.,

jest to pożądane, ale wiąże się to z obowiązkiem uzyskania zależności od kodu, który konstruuje SomeClass.

aby zarządzać odpowiedzialnością za tworzenie zależności, każda aplikacja AngularJS ma injector. Wtryskiwacz jest lokalizatorem usług, który jest odpowiedzialny za budowę i wyszukiwanie zależności.

oto przykład korzystania z serwisu wtryskiwaczy:

Utwórz nowy wtryskiwacz, który może dostarczyć komponenty zdefiniowane w modulemyModule I poproś o usługę greeter z wtryskiwacza., (Zwykle odbywa się to automatycznie przez AngularJS bootstrap).

var injector = angular.injector();var greeter = injector.get('greeter');

pytanie o zależności rozwiązuje problem twardego kodowania, ale oznacza to również, że wtryskiwacz musi być przekazywany przez całą aplikację. Podanie wtryskiwacza łamie prawo Demeter., Aby temu zaradzić, używamy notacji deklaratywnej w naszych szablonach HTML, aby przekazać odpowiedzialność za tworzenie komponentów wtryskiwaczowi, jak w tym przykładzie:

<div ng-controller="MyController"> <button ng-click="sayHello()">Hello</button></div>
function MyController($scope, greeter) { $scope.sayHello = function() { greeter.greet('Hello World'); };}

gdy AngularJS kompiluje HTML, przetwarza

function MyController($scope, greeter) { $scope.sayHello = function() { greeter.greet('Hello World'); };}

dyrektywa 8e7c818a56 ” > , która z kolei prosi wtryskiwacz o utworzenie instancji sterownika i jego zależności.

injector.instantiate(MyController);

wszystko odbywa się za kulisami., Ponieważng-controller odsyła do wtryskiwacza, aby utworzyć instancję klasy, może spełnić wszystkie zależnościMyController bez wiedzy kontrolera o wtryskiwaczu. Kod aplikacji po prostu deklaruje potrzebne zależności, bez konieczności radzenia sobie z wtryskiwaczem. Ta konfiguracja nie łamie prawa Demeter.

C#Edit

przykład wtrysku konstruktora, wtrysku Settera i wtrysku interfejsu w C#

Articles

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *