Uten avhengighet injectionEdit
I det følgende Java eksempel Klient-klassen inneholder en Tjeneste medlem variabel som er initialisert av Klienten constructor. Klienten kontrollerer hvilke gjennomføring av tjenesten brukes, og styrer sin konstruksjon. I denne situasjonen, klienten er sagt å ha en hard-kodet avhengighet på 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 er en alternativ teknikk for å initialisere medlem variabel snarere enn eksplisitt å skape et service objekt som vist ovenfor., Vi kan justere dette for eksempel ved hjelp av ulike teknikker som er beskrevet og illustrert i underkategoriene nedenfor.
Typer avhengighet injectionEdit
Det er minst tre måter en klient objekt kan motta en referanse til en ekstern modul:
constructor injeksjon avhengigheter er gitt gjennom en klient ‘ s klasse constructor. setter injeksjon kunden utsetter en setter metode som de bruker bruker til å injisere avhengighet. grensesnitt injeksjon avhengigheten grensesnitt gir en injektor metode som vil injisere avhengighet til noen klient som sendes til den., Kunder må gjennomføre et grensesnitt som eksponerer en setter metode som tar i mot avhengigheten.
Andre typesEdit
Det er mulig for DI rammer for å ha andre typer injeksjon utover de som er presentert ovenfor.
Testing rammeverk kan også bruke andre typer. Noen moderne testing rammeverk som ikke engang krever at kundene aktivt akseptere dependency injection, og dermed gjør legacy kode testbare. Spesielt i Java-språket, er det mulig å bruke refleksjon for å gjøre private attributter offentlig når testing og dermed akseptere injeksjoner av oppdrag.,
Noen forsøk på Inversjon av Kontroll ikke gi full fjerning av avhengighet, men i stedet bare erstatte en form for avhengighet til en annen. Som en tommelfingerregel, hvis en programmerer kan se på ingenting, men kunden kode og fortelle hva rammeverket brukes, da klienten har en hard-kodet avhengighet av rammen.
Constructor injectionEdit
Denne metoden krever klienten til å gi en parameter i en konstruktør for avhengighet.
Setter injectionEdit
Denne metoden krever klienten til å gi en setter metode for avhengighet.,
Grensesnitt injectionEdit
Dette er ganske enkelt klient publisere en rolle grensesnitt til fuglehunden metoder for kundens avhengigheter. Den kan brukes til å fastslå hvordan de injektor bør snakke med klienten når injisering avhengigheter.
// 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 injeksjon comparisonEdit
Foretrukket når alle avhengigheter kan være konstruert for det første fordi det kan brukes til å sikre klient objekt er alltid i en gyldig tilstand, i motsetning til å ha noen av dens avhengighet referanser bli null (ikke angitt)., Imidlertid, på sin egen, det mangler fleksibilitet til å ha sin avhengigheter endret senere. Dette kan være et første skritt i retning av å gjøre klienten uforanderlig og derfor tråd trygt.
Setter injeksjon comparisonEdit
Krever klienten til å gi en setter metode for hver avhengighet. Dette gir frihet til å manipulere tilstand av avhengighet referanser til enhver tid. Dette gir fleksibilitet, men hvis det er mer enn en avhengighet som skal injiseres, det er vanskelig for kunden å sørge for at alle koplinger er injisert før klienten kunne være tilgjengelig for bruk.,
Fordi disse injeksjoner skje uavhengig av hverandre, og det er ingen måte å fortelle når injektor er ferdig kabling av klienten. Avhengigheten kan være til venstre null rett og slett av injektor unnlate å ringe sin fuglehunden. Dette tvinger sjekk at injeksjonen ble gjennomført fra når klienten er samlet til hver gang det brukes.
Grensesnitt injeksjon comparisonEdit
fordelen av grensesnitt injeksjon er at avhengigheter kan være helt uvitende om sine klienter ennå kan fortsatt motta en referanse til en ny klient, og ved å bruke det, send en referanse-til-selv tilbake til klienten., På denne måten, avhengigheter blitt sprøytebrukere. Nøkkelen er at det å injisere metoden (som bare kunne være en klassisk setter metode) er gitt gjennom et grensesnitt.
En assembler er fortsatt behov for å innføre klienten og dens avhengigheter. Den assembler ville ta en referanse til klienten, kastet den til fuglehunden grensesnitt som angir at avhengighet, og gi det til at avhengighet objekt som ville snu seg rundt for å passere en referanse-til-selv tilbake til klienten.,
For grensesnitt injeksjon for å ha verdi, avhengigheten må gjøre noe i tillegg til å bare passerer tilbake en referanse til seg selv. Dette kan være å opptre som en fabrikk eller sub-assembler for å løse andre avhengigheter, og dermed abstracting noen detaljer fra den viktigste assembler. Det kan være referanse-telling slik at avhengigheten vet hvor mange klienter som bruker det. Hvis avhengigheten opprettholder en samling av klienter, er det senere kunne injisere dem alle med en annen forekomst av seg selv.,
Montere examplesEdit
Manuelt montere i main hånd er en måte å implementere avhengighet injeksjon.
eksempelet over konstruerer objektet grafen manuelt, og deretter aktiverer det på et tidspunkt for å starte det fungerer. Viktig å merke seg er at dette injektor er ikke ren. Den bruker en av de objekter det konstruksjoner. Den har et rent bygg-bare forholdet med ExampleService men blander bygging og bruk av Klienten. Dette bør ikke være vanlig. Det er imidlertid uunngåelig., Akkurat som objekt-orientert programvare trenger en ikke-objekt-orientert statisk metode som main() for å komme i gang, en avhengighet injisert objekt grafen må minst en (fortrinnsvis bare én) inngangspunkt for å få det hele i gang.
Manuell konstruksjon i main-metoden kan ikke være så rett frem og kan innebære å kalle utbyggere, fabrikker, eller annen konstruksjon mønstre som godt. Dette kan være relativt avansert og abstrakt., Linjen er krysset fra manuell dependency injection til rammeverk dependency injection når konstruere koden er ikke lenger tilpasset til programmet og er i stedet universal.
Rammeverk som Spring kan konstruere disse samme objektene og wire dem sammen før du returnerer en referanse til klienten. Alle omtale av de konkrete ExampleService kan flyttes fra kode til konfigurasjonsopplysninger.
Rammeverk som Spring tillate montering detaljer for å være externalized i konfigurasjonsfiler.Denne koden (ovenfor) konstruerer objekter og ledninger dem sammen i henhold til Bønner.xml (nedenfor)., ExampleService er fortsatt bygget selv om det bare er nevnt nedenfor. En lang og komplisert objekt graf kan være definert på denne måten, og den eneste klassen som er nevnt i koden som ville være ett med entry point-metoden, som i dette tilfellet er hilse på().
I eksempelet ovenfor Klienten, og Tjenesten har ikke hatt til å gjennomgå endringer for å være gitt av Våren. De får lov til å forbli enkel POJOs. Dette viser hvordan Våren kan koble tjenester og klienter som er helt uvitende om dens eksistens. Dette kan ikke sies om Våren kommentarer ble lagt til klasser., Ved å holde Våren-spesifikke kommentarer og samtaler fra å spre seg ut blant mange klasser, systemet forblir bare løst avhengig av Våren. Dette kan være viktig hvis systemet har til hensikt å overleve Våren.
valg for å holde POJOs ren kommer ikke uten kostnader. Snarere enn å bruke krefter på å utvikle og vedlikeholde komplekse konfigurasjon-filer, er det mulig å bare bruke merknader til mark klasser og la Våren gjøre resten av arbeidet. Løse koplinger kan være enkelt hvis de følger en konvensjon som passer etter type eller navn. Dette er å velge convention over configuration., Det er også hevdes at når refactoring til en annen ramme, fjerne framework spesifikke merknader ville være en triviell del av oppgaven, og mange injeksjon merknader er nå standardisert.
@Componentpublic class ExampleService { public String getName() { return "World!"; }}
Montering comparisonEdit
De forskjellige injektor implementeringer (fabrikker, service locator, og dependency injection containere) er ikke så forskjellige så langt som dependency injection er bekymret. Hva er det som gjør hele forskjellen er hvor de får lov til å bli brukt., Flytte anrop til en fabrikk eller en tjeneste locator ut av klienten og i hoved-og plutselig main gjør en ganske god dependency injection container.
Ved å flytte all kunnskap av injektoren ut, en ren klient, uten kunnskap om verden utenfor, som er igjen bak. Imidlertid, vil alle objekter som bruker andre objekter kan betraktes som en klient. Objektet som inneholder viktigste er intet unntak. Dette viktigste objektet er ikke avhengighet ved hjelp av injeksjon. Det er faktisk bruker tjenesten locator mønster. Dette kan ikke unngås, fordi valget av service-implementeringer må være gjort på et sted.,
Externalizing avhengigheter i konfigurasjonsfiler, endrer ikke dette faktum. Hva gjør denne virkeligheten del av et godt design er at tjenesten locator er ikke spredt over hele kodebasen. Det er begrenset til ett sted per program. Dette etterlater resten av code base gratis å bruke dependency injection til å gjøre rent kunder.
Dependency Injection PatternEdit
eksemplene som til nå har vært altfor enkle eksempler om å bygge en string., Men, dependency injection mønsteret er mest nyttig når du lager et objekt graf der objekter kommuniserer via meldinger. Objekter bygget i main vil vare livet av programmet. Det typiske mønsteret er å konstruere diagrammet, og deretter kalle en metode på et objekt for å sende flyten av kontroll til objektet grafen. Akkurat som viktigste er hovedkilden til den statiske kode, er dette en metode som er hovedkilden til programmer-ikke-statisk-koden.,
AngularJS exampleEdit
I AngularJS framework, det er bare tre måter en komponent (objekt eller en funksjon) kan direkte tilgang til dets avhengigheter:
- en komponent som kan skape avhengighet, og vanligvis ved hjelp av
new
operatør. - en komponent kan se opp avhengighet, ved å henvise til en global variabel.
- en komponent kan ha avhengighet gått til det der det er nødvendig.
De to første valg for å opprette eller ser opp avhengigheter er ikke optimal fordi de hardt kode avhengighet til komponenten., Dette gjør det vanskelig, om ikke umulig, å endre avhengigheter. Dette er spesielt problematisk i tester, hvor det er ofte ønskelig å gi mock avhengigheter for test isolasjon.
Det tredje alternativet er det mest levedyktige, siden det fjerner ansvaret for å finne avhengighet fra komponent. Avhengigheten er rett og slett levert til komponenten.
I eksempelet ovenfor, SomeClass
er ikke opptatt av å skape eller finne greeter avhengighet, det er rett og slett ga greeter når det er lagt.,
Dette er ønskelig, men det setter ansvar for å få tak i avhengighet av den koden som konstruerer SomeClass
.
for Å behandle ansvar for avhengighet skapelse, hver AngularJS programmet har en injektor. Injektoren er en tjeneste som er adresse som er ansvarlig for bygging og look-up av avhengigheter.
Her er et eksempel på bruk av injektoren service:
du vil Opprette en ny injektor som kan gi komponenter som er definert i myModule
modulen og be om vår greeter service fra injektor., (Dette gjøres vanligvis automatisk av AngularJS bootstrap).
var injector = angular.injector();var greeter = injector.get('greeter');
Be om avhengigheter løser problemet med hardt koding, men det betyr også at injektoren må være bestått gjennom hele programmet. Passerer injektor bryter Loven av Demeter., For å bøte på dette, bruker vi en deklarativ notasjon i vår HTML-maler, til hånd ansvar for å skape komponenter over til sprøyta, som i dette eksemplet:
<div ng-controller="MyController"> <button ng-click="sayHello()">Hello</button></div>
function MyController($scope, greeter) { $scope.sayHello = function() { greeter.greet('Hello World'); };}
Når AngularJS kompilerer HTML, det behandler ng-controller
direktiv, som i sin tur ber injektor for å opprette en forekomst av kontrolleren og dens avhengigheter.
injector.instantiate(MyController);
Dette er gjort bak kulissene., Fordi ng-controller
utsetter injektoren til instantiate klassen, det kan tilfredsstille alle avhengigheter av MyController
uten kontrolleren noen gang å vite om injektor. Programmet koden bare erklærer avhengigheter det er behov for, uten å måtte hanskes med injektor. Dette oppsettet ikke bryte Loven av Demeter.
C#Rediger
Eksempel i Konstruktøren injeksjon, Setter injeksjon og Grensesnitt injeksjon på C#