L'injection de dépendances
Principe de base
L’injection de dépendances est une implémentation du pattern IoC (Inversion of Control ou inversion des contrôles, en français). Le principe de ce pattern est de casser les dépendances entre les éléments.
Dans une organisation classique, un élément est responsable de la gestion de l’instanciation et de la durée de vie de ses dépendances. Cela crée un lien fort entre l’élément et ses dépendances.
class MyElement {
private myDependency: Dependency;
constructor() {
}
doSomething() => {
this.myDependency = new Dependency();
this.myDependency.doSomething();
}
}
Le pseudo-code précédent déclare une classe MyElement contenant une méthode doSomething. Dans cette méthode, une nouvelle instance de la classe Dependency est créée pour appeler sa méthode doSomething().
Le code précédent crée une dépendance forte entre MyElement et Dependency.
Le principe de l’injection de dépendances est de déléguer l’instanciation et la gestion de la durée de vie des dépendances à un élément externe.
class MyElement {
constructor(private myDependency: Dependency) {}
doSomething() => {
this.myDependency.doSomething();
}
}
La classe MyElement a été modifiée pour utiliser l’injection de dépendances. Au lieu d’instancier la classe Dependency dans sa méthode doSomething, une instance de cette classe sera passée...
Injection de dépendances dans Angular
Dans le cadre d’Angular, un composant peut avoir besoin d’un service, on dit alors que le composant est dépendant du service. Le framework Angular joue alors le rôle de gestionnaire de dépendances.
La première étape afin d’utiliser l’injection de dépendances est d’enregistrer les dépendances de notre application. Angular permet d’effectuer cette opération à différents niveaux.
1. Enregistrement global
Le niveau le plus haut est celui de l’application elle-même. Lorsqu’une dépendance est déclarée au niveau de l’application, à chaque fois qu’un élément du framework demande cette dépendance, ce sera la même instance qui lui sera retournée. Les dépendances déclarées à ce niveau agissent donc comme des singletons.
La déclaration de dépendances à ce niveau s’effectue lors de la déclaration du module de l’application. Il faut utiliser la propriété providers du décorateur @NgModule. Dans ce décorateur, la manière la plus simple d’enregistrer des dépendances est de lister les classes à injecter.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { PommeService } from './shared/pomme.service';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [
PommeService
],
bootstrap: [AppComponent]
})
export class AppModule { }
Dans l’exemple ci-dessus, le module déclare...
Provider
Jusqu’à présent, seule la méthode la plus simple d’enregistrement a été abordée : en référençant le type de l’élément à injecter dans la propriété provider des décorateurs @NgModule et @Component. Il existe des méthodes plus complexes, correspondant à des besoins plus spécifiques.
1. UseClass
Afin d’enregistrer une dépendance, il est possible d’utiliser le provider de classe UseClass. Celui-ci sert à injecter une version alternative de l’implémentation d’une classe. Cela peut être utile à des fins de tests ou encore lorsqu’un composant nécessite une implémentation différente d’un service.
Pour utiliser ce provider, il faut fournir à la propriété providers des décorateurs @NgModule ou @Component un objet contenant deux propriétés. La première propriété est provide et correspond au type que l’on souhaite enregistrer. La deuxième est useClass, cette propriété doit contenir le type que doit retourner le module d’injection de dépendances lorsqu’un élément demande le type inscrit dans provide.
Il est également possible d’enregistrer un type de manière conditionnelle, en utilisant une expression ternaire par exemple dans la propriété useClass. Cependant il faut garder en tête qu’une fois la dépendance enregistrée, la condition ne sera plus exécutée.
providers: [
{
provide: PommeService,
useClass: environment.production
? PommeService
...