Proveedores múltiples en Angular

dependency-injection
Foto de Marita Kavelashvili en Unsplash

Gracias al sistema de inyección de dependencias que nos ofrece Angular, podremos inyectar a una clase los servicios necesarios para funcionar correctamente. No obstante, si tenemos varios servicios, podemos agruparlos bajo un mismo paraguas. Crearemos un InjectionToken que aglutine dichos servicios y así inyectar solo el token y no todos los servicios uno a uno de forma separada, es decir, tener proveedores múltiples. Los pasos básicamente serían:

  1. Crear el InjectionToken
  2. Registrar las clases en el módulo para que su «provide» sea el token, «useClass» la clase a usar y la propiedad «multi» a true
  3. Inyectar el token en las clases consumidoras.

Caso de ejemplo en el patrón Strategy

Esto es, tomando el ejemplo del artículo del patrón Strategy, tenemos que las estrategias cumplen una determinada interfaz y todas ellas se inyectan de forma separada en el constructor de la clase “Context”. Dichas estrategias se agrupan en un array para ser recorridas y poderse ejecutar cuando toquen.

Ahora bien, ¿Qué te parecería si en vez de inyectar una a una las estrategias se inyectase sólo el token? ¿Suena bien, verdad? De esta manera cada vez que se vaya a crear una estrategia nueva sólo hay que registrarla en el módulo. ¡Veamos cómo!

Primero de todo tenemos que crear un token de inyección que pueda agrupar todas esas clases que cumplen esa interfaz:

import { InjectionToken } from '@angular/core';
import { IStrategy } from './iStrategy';
 
export const StrategyToken = new InjectionToken<Array<IStrategy>>('iStrategy');

Ahora que tenemos creado el token, tendremos que registrar los servicios indicando a Angular que dicho token incluye los servicios de forma múltiple de la siguiente forma:

import { NgModule } from '@angular/core';
import { ContextService } from './context.service';
import * as strategies from './strategies/index';
 
@NgModule({
    declarations: [],
    exports: [],
    imports: [],
    providers: [
        ContextService,
        { provide: strategies.StrategyToken, useClass: strategies.DryStrategy, multi: true },
        { provide: strategies.StrategyToken, useClass: strategies.SubHumidStrategy, multi: true },
        { provide: strategies.StrategyToken, useClass: strategies.HumidStrategy, multi: true }
    ]
})
export class PatternModule { }

Nota: Previamente, se ha incluído el token en el fichero index.ts (barrel file) para tener un punto en común de todo el pack de clases.

Vemos que el registro de la clase “Context” sigue igual, pero ahora el registro de las clases de estrategias de hace de forma diferente de su forma antigua. Esto es, ahora las estrategias están agrupadas por un mismo token de inyección (StrategyToken) con el parámetro “multi” a true.

Utilizando esta forma de tener proveedores múltiples, sólo nos quedaría modificar el consumo de dichos servicios por la clase “Context”: Puede hacerse de dos formas:

Inyectar la clase “Injector” y luego coger las estrategias con su método «get«:

 public constructor(
        private injector: Injector
    ) {
        this._strategies = injector.get(strategies.StrategyToken);
    }

Inyectar el array de estrategias del token con @Inject:

public constructor(
        @Inject(strategies.StrategyToken) private _strategies: Array<strategies.IStrategy> 
    ) {
    }

Con esta modificación, en la clase “Context”, ya no se necesitará proveerle de una nueva estrategia cuando se vaya a crear, puesto que estará asociada al token configurado en el registro del módulo.

Puedes descargar el código del artículo en GitHub

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *