Vinkelafhængighedsinjektion forklaret med eksempler

Hvad er afhængighedsinjektion?

Motivering

Afhængighedsinjektion kaldes ofte mere simpel som DI. Paradigmet findes i hele Angular. Det holder koden fleksibel, testbar og ændret. Klasser kan arve ekstern logik uden at vide, hvordan man opretter den. Enhver forbruger af disse klasser behøver heller ikke at vide noget.

DI sparer både klasser og forbrugere fra at skulle vide mere end nødvendigt. Alligevel er koden så modulær som den var før takket være de mekanismer, der understøtter DI i vinkel.

Tjenester er en vigtig velgører for DI. De er afhængige af paradigmet for injektion i forskellige forbrugere. Disse forbrugere kan derefter drage fordel af denne service og / eller videresende den andre steder.

Service er ikke alene. Direktiver, rør, komponenter og så videre: ethvert skema i Angular drager fordel af DI på en eller anden måde.

Injektorer

Injektorer er datastrukturer, der gemmer instruktioner, der beskriver, hvor og hvordan tjenester dannes. De fungerer som formidlere inden for Angular DI-systemet.

Modul-, direktiv- og komponentklasser indeholder metadata, der er specifikke for injektorer. En ny injektorinstans ledsager hver enkelt af disse klasser. På denne måde afspejler applikationstræet dets hierarki af injektorer.

Den providers: []metadata accepterer tjenester, der derefter registrere med klassen injektor. Dette udbyderfelt tilføjer de nødvendige instruktioner for, at en injektor kan fungere. En klasse (forudsat at den har afhængigheder) starter en tjeneste ved at tage dens klasse som sin datatype. Injektoren justerer denne type a opretter en forekomst af denne service på klassens vegne.

Selvfølgelig kan klassen kun instantiere, hvad injektoren har instruktioner til. Hvis klassens egen injektor ikke har registreret tjenesten, spørger den sin forælder. Så videre og så videre, indtil enten når en injektor med tjenesten eller applikationsroden.

Tjenester kan registreres på en hvilken som helst injektor i applikationen. Tjenester går i providers: []metadatafeltet for klassemoduler, direktiver eller komponenter. Klassen 'børn kan iværksætte en tjeneste, der er registreret i klassen' injektor. Barninjektorer er trods alt tilbagefald på forældreinjektorer.

Afhængighedsinjektion

Se skeletterne for hver klasse: service, modul, direktiv og komponent.

// service import { Injectable } from '@angular/core'; @Injectable({ providedIn: /* injector goes here */ }) export class TemplateService { constructor() { } }
// module import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; @NgModule({ imports: [ CommonModule ], declarations: [], providers: [ /* services go here */ ] }) export class TemplateModule { }
// directive import { Directive } from '@angular/core'; @Directive({ selector: '[appTemplate]', providers: [ /* services go here */ ] }) export class TemplateDirective { constructor() { } }
//component import { Component } from '@angular/core'; @Component({ selector: 'app-template', templateUrl: './template.component.html', styleUrls: ['./template.component.css'], providers: [ /* services go here */ ] }) export class TemplateComponent { // class logic ... }

Hvert skelet kan registrere tjenester til en injektor. Faktisk TemplateService er en tjeneste. Fra og med Angular 6 kan tjenester nu registreres hos injektorer ved hjælp af @Injectablemetadata.

Under alle omstændigheder

Bemærk metadataene providedIn: string( @Injectable) og providers: []( @Directive, @Componetog @Module). De fortæller injektorer, hvor og hvordan man opretter en tjeneste. Ellers ville injektorer ikke vide, hvordan de skal instantieres.

Hvad hvis en tjeneste har afhængigheder? Hvor ville resultaterne gå? Udbydere besvarer disse spørgsmål, så injektorer kan instantiere ordentligt.

Injektorer udgør rygraden i DI-rammen. De gemmer instruktioner til at instantiere tjenester, så forbrugerne ikke behøver det. De modtager serviceinstanser uden at skulle vide noget om kildeafhængigheden!

Jeg skal også bemærke, at andre skemaer uden injektorer stadig kan bruge afhængighedsinjektion. De kan ikke registrere yderligere tjenester, men de kan stadig starte fra injektorer.

Service

Den providedIn: stringmetadata af @Injectablebestemmer, hvilke Injector at registrere med. Ved hjælp af denne metode og afhængigt af, om tjenesten bliver brugt, kan tjenesten muligvis ikke registreres hos injektoren. Angular kalder dette trærystning .

Som standard er værdien indstillet til ‘root’. Dette oversættes til rodinjektoren til applikationen. Dybest set sætter du feltet til at ‘root’gøre tjenesten tilgængelig overalt.

Hurtig note

Som tidligere nævnt falder børnesprøjter tilbage på deres forældre. Denne tilbagefaldsstrategi sikrer, at forældre ikke behøver at omregistrere sig til hver injektor. Se denne artikel om tjenester og injektorer for en illustration af dette koncept.

Registrerede tjenester er singletoner . Betydningen, instruktionerne til at starte tjenesten findes kun på en injektor. Dette forudsætter, at det ikke er eksplicit registreret andetsteds.

Modul, direktiv og komponent

Moduler og komponenter har hver deres injektorinstans. Dette er tydeligt i betragtning af providers: []metadatafeltet. Dette felt tager en række tjenester og registrerer dem med injektoren i modulet eller komponentklassen. Denne tilgang sker i de @NgModule, @Directiveeller @Componentdekoratører.

Denne strategi udelader trærystning eller valgfri fjernelse af ubrugte tjenester fra injektorer. Serviceinstanser lever på deres injektorer hele modulets eller komponentens levetid.

Instantierende referencer

Henvisninger til DOM kan instantieres fra enhver klasse. Husk, at referencer stadig er tjenester. De adskiller sig fra traditionelle tjenester ved at repræsentere tilstanden for noget andet. Disse tjenester inkluderer funktioner til at interagere med deres reference.

Direktiver har konstant behov for DOM-referencer. Direktiver udfører mutationer på deres værtselementer gennem disse referencer. Se følgende eksempel. Direktivets injektor instantierer en reference af værtselementet til klassens konstruktør.

// directives/highlight.directive.ts import { Directive, ElementRef, Renderer2, Input } from '@angular/core'; @Directive({ selector: '[appHighlight]' }) export class HighlightDirective { constructor( private renderer: Renderer2, private host: ElementRef ) { } @Input() set appHighlight (color: string) { this.renderer.setStyle(this.host.nativeElement, 'background-color', color); } }
// app.component.html 

Highlighted Text!

Renderer2bliver også instantieret. Hvilken injektor kommer disse tjenester fra? Nå, hver tjenestes kildekode kommer fra @angular/core. Disse tjenester skal derefter registreres med applikationens rodinjektor.

import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { HighlightDirective } from './directives/highlight.directive'; @NgModule({ declarations: [ AppComponent, HighlightDirective ], imports: [ BrowserModule ], providers: [], bootstrap: [ AppComponent ] }) export class AppModule { }

Et tomt udbyders array !? Ikke at frygte. Angular registrerer automatisk mange tjenester med rodinjektoren. Dette inkluderer ElementRefog Renderer2. I dette eksempel styrer vi værtselementet gennem dets interface, der stammer fra instantiering af ElementRef. Renderer2lader os opdatere DOM gennem Angular's visningsmodel.

You can read more about views from this article. They are the preferred method for DOM/view updates in Angular applications.

It is important recognize the role that injectors play in the above example. By declaring variable types in the constructor, the class obtains valuable services. Each parameter’s data type maps to a set of instructions within the injector. If the injector has that type, it returns an instance of said type.

Instantiating Services

The Services and Injectors article explains this section to an extent. Though, this section rehashes the previous section or the most part. Services will often provide references to something else. They may just as well provide an interface extending a class’ capabilities.

The next example will define a logging service that gets added to a component’s injector via its providers: [] metadata.

// services/logger.service.ts import { Injectable } from '@angular/core'; @Injectable() export class LoggerService { callStack: string[] = []; addLog(message: string): void { this.callStack = [message].concat(this.callStack); this.printHead(); } clear(): void { this.printLog(); this.callStack = []; console.log(“DELETED LOG”); } private printHead(): void  null);  private printLog(): void { this.callStack.reverse().forEach((log) => console.log(message)); } }
// app.component.ts import { Component } from '@angular/core'; import { LoggerService } from './services/logger.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', providers: [LoggerService] }) export class AppComponent { constructor(private logger: LoggerService) { } logMessage(event: any, message: string): void { event.preventDefault(); this.logger.addLog(`Message: ${message}`); } clearLog(): void { this.logger.clear(); } }
// app.component.html 

Log Example

SUBMIT

Delete Logged Messages

CLEAR

Focus on the AppComponent constructor and metadata. The component injector receives instructions from the provider’s metadata field containing LoggerService. The injector then knows what to instantiate LoggerService from requested in the constructor.

The constructor parameter loggerService has the type LoggerService which the injector recognizes. The injector follows through with the instantiation as mentioned.

Conclusion

Dependency injection (DI) is a paradigm. The way it works in Angular is through a hierarchy of injectors. A class receives its resources without having to create or know about them. Injectors receive instruction and instantiate a service depending on which one was requested.

DI dukker meget op i Angular. Den officielle Angular-dokumentation forklarer, hvorfor paradigmet er så udbredt. De fortsætter også med at beskrive de mange brugssager for DI på en vinklet måde ud over det, der blev diskuteret i denne artikel. Tjek det ved at klikke nedenfor!

Mere om afhængighedsinjektion:

  • Introduktion til vinkelafhængighedsinjektion
  • Hurtig introduktion til afhængighedsinjektion