Injektiranje kutne ovisnosti objašnjeno primjerima

Što je injekcija ovisnosti?

Motivacija

Injektiranje ovisnosti često se jednostavnije naziva DI. Paradigma postoji u cijelom kutnom. Kôd održava fleksibilnim, provjerljivim i promjenjivim. Predavanja mogu naslijediti vanjsku logiku, a da ne znaju kako je stvoriti. Potrošači tih klasa također ne trebaju znati ništa.

DI štedi nastavu i potrošače da ne moraju znati više nego što je potrebno. Ipak, kôd je modularan kao i prije, zahvaljujući mehanizmima koji podržavaju DI u kutnom.

Usluge su ključni dobrotvor DI-a. Oslanjaju se na paradigmu za injekcije kod različitih potrošača. Ti potrošači tada mogu iskoristiti tu uslugu i / ili je proslijediti negdje drugdje.

Usluge nisu same. Direktive, cijevi, dijelovi i tako dalje: svaka shema u kutnom obliku na neki ili drugi način koristi od DI.

Injektori

Injektori su podatkovne strukture koje pohranjuju upute s detaljima gdje i kako se oblikuju usluge. Djeluju kao posrednici unutar sustava Angular DI.

Klase modula, direktiva i komponenata sadrže metapodatke specifične za mlaznice. Nova instalacija injektora prati svaku od ovih klasa. Na taj način, stablo aplikacije odražava svoju hijerarhiju injektora.

providers: []Metapodataka prihvaća usluge koje potom registriraju s klase injektora. Ovo polje dobavljača dodaje upute potrebne za rad mlaznice. Klasa (pod pretpostavkom da ima ovisnosti) pokreće uslugu uzimajući njezinu klasu kao svoj tip podataka. Mlaznica poravnava ovu vrstu a stvara instancu te usluge u ime klase.

Naravno, klasa može izraditi samo ono za što injektor ima upute. Ako vlastiti injektor klase nema registriranu uslugu, tada postavlja upit roditelju. Tako dalje i tako dalje sve dok ne dođete do mlaznice s uslugom ili korijenom aplikacije.

Usluge se mogu registrirati na bilo kojoj brizgalici unutar aplikacije. Usluge idu u providers: []polje metapodataka modula, smjernica ili komponenata klase. Djeca razreda mogu stvoriti uslugu registriranu u mlaznici klase. Na kraju ipak dječji injektori zamjenjuju se roditeljskim injektorima.

Injekcija ovisnosti

Pogledajte kosture za svaku klasu: uslugu, modul, direktivu i komponentu.

// 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 ... }

Svaki kostur može registrirati usluge injektoru. U stvari, TemplateService je usluga. Od Angular 6, usluge se sada mogu registrirati s injektorima pomoću @Injectablemetapodataka.

U svakom slučaju

Primijetite metapodatke providedIn: string( @Injectable) i providers: []( @Directive, @Componeti @Module). Oni injektorima govore gdje i kako stvoriti uslugu. Inače, injektori ne bi znali kako napraviti instancu.

Što ako usluga ima ovisnosti? Kamo bi otišli rezultati? Pružatelji usluga odgovaraju na ta pitanja kako bi se injektori mogli pravilno pokrenuti.

Injektori čine okosnicu DI okvira. Oni pohranjuju upute za instanciju usluga tako da potrošači to ne moraju. Oni primaju instance usluga bez potrebe da znaju bilo što o ovisnosti o izvoru!

Također bih trebao primijetiti da druge sheme bez mlaznica i dalje mogu koristiti ubrizgavanje ovisnosti. Ne mogu registrirati dodatne usluge, ali još uvijek mogu pokrenuti postupak ubrizgavanja.

Servis

providedIn: stringMetapodataka @Injectableodređuje koje injektor prijaviti. Koristeći ovu metodu, i ovisno o tome koristi li se usluga, usluga se može registrirati ili ne registrirati na mlaznici. Angular ovo naziva drhtanje .

Prema zadanim postavkama vrijednost je postavljena na ‘root’. To se prevodi u korijenski injektor aplikacije. U osnovi, postavljanjem polja ‘root’čini uslugu dostupnom bilo gdje.

Brza napomena

Kao što je prethodno spomenuto, djeca injektora zamjenjuju se roditeljima. Ova rezervna strategija osigurava da se roditelji ne moraju ponovno registrirati za svaku injekciju. Pogledajte članak o uslugama i mlaznicama za ilustraciju ovog koncepta.

Registrirane usluge su pojedinačne . Znači, upute za instanciju usluge postoje samo na jednoj brizgalici. To pretpostavlja da drugdje nije izričito registrirano.

Modul, smjernica i komponenta

Svaki od modula i komponenata ima vlastiti primjer injektora. To je očito s obzirom na providers: []polje metapodataka. Ovo polje uzima niz usluga i registrira ih injektorom klase modula ili komponente. Ovaj pristup se događa u @NgModule, @Directiveili @Componentobrtnici.

Ova strategija izostavlja drhtanje drveća ili neobavezno uklanjanje neiskorištenih usluga s mlaznica. Instalacijski servisi žive na svojim brizgaljkama tijekom vijeka trajanja modula ili komponente.

Instancirajuće reference

Reference na DOM mogu se stvoriti iz bilo koje klase. Imajte na umu da su reference i dalje usluge. Razlikuju se od tradicionalnih usluga po tome što predstavljaju stanje nečega drugog. Te usluge uključuju funkcije za interakciju s njihovim referencama.

Direktive stalno trebaju reference na DOM. Direktive vrše mutacije na elementima domaćina putem ovih referenci. Pogledajte sljedeći primjer. Injektor direktive instancira referencu elementa domaćina u konstruktor klase.

// 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!

Renderer2također postaje instanciran. Iz koje mlaznice dolaze ove usluge? Pa, izvorni kod svake usluge dolazi @angular/core. Te se usluge tada moraju registrirati s korijenskim injektorom aplikacije.

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 { }

Prazan niz pružatelja !? Da se ne bojim. Angular automatski registrira mnoge usluge s korijenskim injektorom. To uključuje ElementRefi Renderer2. U ovom primjeru upravljamo elementom domaćina kroz njegovo sučelje koje proizlazi iz instancije ElementRef. Renderer2omogućuje nam ažuriranje DOM-a kroz model prikaza Angulala.

Više o pogledima možete pročitati iz ovog članka. Oni su preferirana metoda za ažuriranja DOM-a / pogleda u Angular aplikacijama.

Važno je prepoznati ulogu koju injektori imaju u gornjem primjeru. Deklariranjem tipova varijabli u konstruktoru, klasa dobiva vrijedne usluge. Tip podataka svakog parametra preslikava se na niz uputa unutar mlaznice. Ako injektor ima taj tip, vraća primjerak navedenog tipa.

Instancirajuće usluge

Članak o uslugama i injektorima u određenoj mjeri objašnjava ovaj odjeljak. Iako ovaj odjeljak preoblikuje prethodni odjeljak ili veći dio. Usluge će često pružiti reference na nešto drugo. Oni jednako tako mogu pružiti sučelje koje proširuje mogućnosti klase.

Sljedeći će primjer definirati uslugu bilježenja koja se dodaje injektoru komponente putem svojih providers: []metapodataka.

// 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 shows up a lot in Angular. The official Angular documentation explains why the paradigm is so prevalent. They also go on to describe the numerous use-cases for DI in Angular way beyond what was discussed in this article. Check it out by clicking below!

More on dependency injection:

  • Intro to Angular dependency injection
  • Quick intro to dependency injection