Injection de dépendances
Concept¶
- Le but de cette présentation est de faire comprendre le fonctionnement et l'intérêt de l'injection de dépendances.
-
L'intérêt est :
- d'améliorer la modularité d'un projet ;
- de faciliter les tests ;
- de ne pas créer ses objets soi-même.
- Nous l'illustrons avec la modélisation d'un jeu de golf (inspiration de https://docs.microsoft.com/fr-fr/aspnet/mvc/overview/older-versions/hands-on-labs/aspnet-mvc-4-dependency-injection).
Présentation d'un jeu de Golf standard¶

Le golfeur n'a pas à se soucier du club qu'il va utiliser car :
- au début du parcours, un caddy accompagne le golfeur. Celui-ci possède un sac de golf avec plusieurs clubs.
- Pendant le parcours, le caddy lui fournit le club adapté à la situation
De cette façon :
- Le caddy est fournisseur de services.
- Le golfeur est consommateur des services fournis.
Le concept d'injection de dépendances est un pattern1 qui
est implémenté dans de nombreux frameworks Java parmi lesquels :
- JavaEE avec les EJBs (Enterprise Java Beans)
- Spring framework
- Google Guice2 (que nous utiliserons par la suite)
Quelques explications : https://github.com/google/guice/wiki/Motivation (prenez le temps de lire cette page plus tard, elle est très instructive).
Nous allons voir comment organiser les classes sans et avec injection de dépendances.
Principe de découplage et abstraction (SANS injection de dépendances)¶
Le principe de découplage est important dans le développement logiciel, car il permet une bonne évolutivité du code tout en facilitant la maintenance et diminuant le risque d'effets de bord.
Interface Club (déclaration de service)¶
En Java, l'abstraction est gérée en déclarant des interfaces de services.
Notez que dans une interface, toutes les méthodes sont implicitement publiques. Ainsi, on ne déclare pas le mot-clé public devant les méthodes. Pour de plus amples détails : http://docs.oracle.com/javase/tutorial/java/concepts/interface.html.
Il est nécessaire de fournir des implémentation de ce service.
Classe Putter, implémentation d'un club (Implémentation de service)¶
L'implémentation est effectuée comme suit. À noter qu'elle est placée dans un sous-package afin de mieux illustrer le couplage qui apparaîtra dans la classe Caddy.
D'autres implémentations sont nécessaires pour les autres services (clubs).
Classe Ball¶
La classe Ball représente une balle de golf à une position sur le parcours (attribut position).
Classe du Caddy (Fournisseur de services)¶
La classe du caddy :
- possède les différents clubs ;
- sait quel club utiliser en fonction des conditions.
À noter le couplage entre Caddy et les deux clubs Putter et Wood. La dépendance est marquée à deux endroits :
- dans la section d'imports :
new :
Enum des Conditions¶
La classe d'enum des différentes conditions de jeu.
Classe Player¶
Classe App¶
Pour finir, le point d'entrée principal du programme qui fait avancer une balle de golf sur un parcours.

Exercice
Objectif : Coder le mini-projet de Golf (15 minutes) qui servira de base à la version avec injection de dépendances.
- À l'aide de Maven (dans le dossier
injectiondu TP)- créer la structure du projet (cf. cours Prérequis et
archetype) - nom de projet: golf
- créer la structure du projet (cf. cours Prérequis et
- Importer le projet dans IntelliJ (cf. cours Prérequis)
- Copier l'interface Club
- Copier l'implémentation Putter qui fait avancer la balle de golf de 10 mètres
- Coder l'implémentation Wood qui fait avancer la balle de golf de 100 mètres
- Coder les autres classes du projet
- Dans une classe App, coder la fonction
main - Commiter/pousser
C'est rapide, tout le code est dans le support !
Explications¶
La classe Caddy dans l'exemple précédent joue 2 rôles :
- le rôle de conteneur en cachant les implémentations de Club (en attribut)
- le rôle de résolveur de dépendances en connaissant les implémentations d'interfaces à utiliser selon les conditions du terrain
L'abstraction est illustrée dans la classe Player où il n'y a aucune trace des classes Putter et Wood ! Les classes concrètes sont manipulées à travers l'interface Club.
Pour autant, il y a un couplage au niveau de la classe Caddy puisque cette dernière est obligée d'instancier les classes concrètes.
Utilisation d'injection de dépendances¶
Injection de dépendances avec Google Guice¶
Google Guiceest un framework d'injection de dépendances.- L'injection permet de supprimer le couplage entre le golfeur et son caddy ainsi qu'entre le caddy et ses clubs.
- Techniquement, l'opération est rendue possible grâce à la JVM qui permet la manipulation du bytecode à la volée.

L'instanciation des objets qui ont des dépendances va être déléguée au conteneur Guice. C'est à ce dernier que l'on va devoir s'adresser pour récupérer des instances.
Classe App avec google Guice¶
Référence :
- https://google.github.io/guice/api-docs/4.2.2/javadoc/com/google/inject/Guice.html
- https://google.github.io/guice/api-docs/4.2.2/javadoc/com/google/inject/Injector.html
Classe MainModule¶
Tout le code de résolution des dépendances est dans la classe MainModule qui indique quelle classe utiliser pour quel service.
Référence :
- https://google.github.io/guice/api-docs/4.2.2/javadoc/com/google/inject/AbstractModule.html
- https://google.github.io/guice/api-docs/4.2.2/javadoc/com/google/inject/name/Names.html
Classe Caddy¶
Dès lors, l'utilisation de Guice permet d'injecter les dependances comme dans le code ci-dessous.
Référence :
- https://google.github.io/guice/api-docs/4.2.2/javadoc/com/google/inject/name/Named.html
- https://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/Inject.html
- On note qu'il n'y a plus aucun couplage avec une implémentation de
ClubdansCaddy(Suppression desimportetnew). - On peut ajouter de nouvelles implémentations de
Clubsans recompilerCaddy.

Exercice
Objectif : Mise en place d'un système d'injection de dépendances. Intégrer google Guice au mini-projet de Golf (30 minutes)
- Pensez à commiter et pousser la version précédente du golf
- Rajouter la dépendance dans le
pom.xml
<dependencies>
...
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>5.0.1</version>
</dependency>
...
</dependencies>
- Rajouter la classe
MainModule - Modifier la classe
Caddy - Modifier le
mainpour exécuter ce programme - Coder une nouvelle implémentation de l'interface Club nommé
PutterExperimental. - Ajouter une deuxième classe avec un
mainet unMainModuleExperimentalpour utiliser la nouvelle implémentation deClub(ExperimentalPutter) pour illustrer la possibilité de créer une autre application qui utilise un autre type de Putter sans avoir à modifierCaddy. - Commiter régulièrement
- Ajouter un tag
injectionà la fin du TD - Pousser
Nous verrons plus tard comment lancer ce type d'application manuellement. Contentez-vous d'utiliser l'IDE pour le moment.
Les architectures en couches ont un recours massif à l'injection de dépendances. Elles limitent -entre autres- les risques de dépendances circulaires, signe d'une erreur de conception.