Iniezione di successione e dipendenza

Ho una serie di componenti angular2 che dovrebbero essere tutti iniettati. Il mio primo pensiero è che sarebbe meglio creare una super class e iniettare il servizio lì. Ognuno dei miei componenti estenderebbe quindi quella superclass ma questo approccio non funziona.

Esempio semplificato:

export class AbstractComponent { constructor(private myservice: MyService) { // Inject the service I need for all components } } export MyComponent extends AbstractComponent { constructor(private anotherService: AnotherService) { super(); // This gives an error as super constructor needs an argument } } 

Potrei risolvere questo problema iniettando MyService all’interno di ogni singolo componente e usarlo per la chiamata a super() , ma si tratta sicuramente di una sorta di assurdo.

Come organizzare correttamente i miei componenti in modo che ereditino un servizio dalla super class?

    Potrei risolvere questo problema iniettando MyService all’interno di ogni singolo componente e userei quell’argomento per la chiamata a super (), ma si tratta sicuramente di una sorta di assurdo.

    Non è assurdo. Questo è il modo in cui funzionano i costruttori e l’iniezione del costruttore.

    Ogni class iniettabile deve dichiarare le dipendenze come parametri del costruttore e se anche la superclass ha delle dipendenze, queste devono essere elencate anche nel costruttore della sottoclass e passate alla superclass con la chiamata super(dep1, dep2) .

    Passare attorno a un iniettore e acquisire dipendenze ha imperativamente gravi svantaggi.

    Nasconde le dipendenze che rendono il codice più difficile da leggere.
    Violare le aspettative di chi ha familiarità con il funzionamento di Angular2 DI.
    Interrompe la compilazione offline che genera il codice statico per sostituire il DI dichiarativo e imperativo per migliorare le prestazioni e ridurre le dimensioni del codice.

    Soluzione aggiornata, impedisce la generazione di più istanze di myService utilizzando l’iniettore globale.

     import {Injector} from '@angular/core'; import {MyServiceA} from './myServiceA'; import {MyServiceB} from './myServiceB'; import {MyServiceC} from './myServiceC'; export class AbstractComponent { protected myServiceA:MyServiceA; protected myServiceB:MyServiceB; protected myServiceC:MyServiceC; constructor(injector: Injector) { this.settingsServiceA = injector.get(MyServiceA); this.settingsServiceB = injector.get(MyServiceB); this.settingsServiceB = injector.get(MyServiceC); } } export MyComponent extends AbstractComponent { constructor( private anotherService: AnotherService, injector: Injector ) { super(injector); this.myServiceA.JustCallSomeMethod(); this.myServiceB.JustCallAnotherMethod(); this.myServiceC.JustOneMoreMethod(); } } 

    Ciò garantirà che MyService possa essere utilizzato all’interno di qualsiasi class che estenda AbstractComponent senza la necessità di iniettare MyService in ogni class derivata.

    Ci sono alcuni svantaggi di questa soluzione (vedi Ccomment di @ Günter Zöchbauer sotto la mia domanda iniziale):

    • Iniettare l’iniettore globale è solo un miglioramento quando ci sono diversi servizi che devono essere iniettati in molti posti. Se hai solo un servizio condiviso, probabilmente è meglio / più facile iniettare quel servizio all’interno della class derivata (es)
    • La mia soluzione e la sua alternativa proposta hanno sia lo svantaggio che rendono più difficile vedere quale class dipende da quale servizio.

    Per una spiegazione molto ben scritta dell’iniezione di dipendenza in Angular2, vedere questo post del blog che mi ha aiutato molto a risolvere il problema: http://blog.thoughtram.io/angular/2015/05/18/dependency-injection-in-angular- 2.html

    Invece di iniettare manualmente tutti i servizi, ho creato una class che fornisce i servizi, ad esempio, ottiene i servizi iniettati. Questa class viene quindi iniettata nelle classi derivate e passata alla class base.

    Classe derivata:

     @Component({ ... providers: [ProviderService] }) export class DerivedComponent extends BaseComponent { constructor(protected providerService: ProviderService) { super(providerService); } } 

    Classe base:

     export class BaseComponent { constructor(protected providerService: ProviderService) { // do something with providerService } } 

    Classe di servizio:

     @Injectable() export class ProviderService { constructor(private _apiService: ApiService, private _authService: AuthService) { } } 

    Se la class genitore è stata acquisita da un plug-in di terze parti (e non puoi cambiare la fonte) puoi farlo:

     import { Injector } from '@angular/core'; export MyComponent extends AbstractComponent { constructor( protected injector: Injector, private anotherService: AnotherService ) { super(injector.get(MyService)); } } 

    o il modo migliore (mantenere solo un parametro nel costruttore):

     import { Injector } from '@angular/core'; export MyComponent extends AbstractComponent { private anotherService: AnotherService; constructor( protected injector: Injector ) { super(injector.get(MyService)); this.anotherService = injector.get(AnotherService); } } 

    Invece di iniettare un servizio che ha tutti gli altri servizi come dipendenze, in questo modo:

     class ProviderService { constructor(private service1: Service1, private service2: Service2) {} } class BaseComponent { constructor(protected providerService: ProviderService) {} ngOnInit() { // Access to all application services with providerService this.providerService.service1 } } class DerivedComponent extends BaseComponent { ngOnInit() { // Access to all application services with providerService this.providerService.service1 } } 

    Vorrei saltare questo passaggio extra e aggiungere semplicemente tutti i servizi in BaseComponent, in questo modo:

     class BaseComponent { constructor(protected service1: Service1, protected service2: Service2) {} } class DerivedComponent extends BaseComponent { ngOnInit() { this.service1; this.service2; } } 

    Questa tecnica assume 2 cose:

    1. La tua preoccupazione è interamente correlata all’ereditarietà dei componenti. Molto probabilmente, la ragione per cui sei arrivato a questa domanda è a causa della quantità schiacciante di codice non-dry (WET?) Che devi ripetere in ogni class derivata. Se si desidera usufruire di un singolo punto di ingresso per tutti i componenti e i servizi , sarà necessario eseguire il passaggio aggiuntivo.

    2. Ogni componente estende il BaseComponent

    C’è anche uno svantaggio se decidi di usare il costruttore di una class derivata, dato che dovrai chiamare super() e passare tutte le dipendenze. Sebbene in realtà non vedo un caso d’uso che richiede l’uso del constructor invece di ngOnInit , è del tutto ansible che esista un caso d’uso simile.