Il y a quelques semaines je me suis retrouvé à expliquer le concept d'injection de dépendance à un groupe de développeur après avoir expliqué ce même concept à ma compagne qui n'est pas du tout du milieu, simplement curieuse. J'ai trouvé un exemple qui me paraissait plutôt pas mal pour expliquer tout ça, j'ai développé le raisonnement assez loin ici.

Martha a besoin de Pierre

Imaginons le cas d'une personne que nous appellerons Martha qui a besoin de tailler la haie de son jardin. Son problème c'est qu'elle ne possède pas les outils pour faire ça et quand bien même elle les aurait, elle ne sait pas tailler une haie. Heureusement pour elle, elle connaît très bien un jardinier. Ça fait des années qu'elle appelle Pierre pour  sa haie et que tout va bien.

Maintenant que se passerait-il si Pierre est débordé, malade, en vacances ou déménage dans une autre région ? Martha n'étant habituée à confier son jardin qu'à Pierre, elle serait coincée avec son jardin qui ne serait plus entretenu.

Si on raisonne en termes d'objet on pourrait avoir quelque chose du genre :

Nous avons Martha qui dépend directement de Pierre. Nous somme ici dans un schéma objet très basique.

Martha a besoin d'un jardinier

Si Martha voulait ne pas dépendre exclusivement de Pierre, elle pourrait changer de méthode. Plutôt que d'appeler directement Pierre, elle pourrait poster systématiquement une annonce demandant un jardinier et le premier jardinier qui répond taillera la haie de Martha. Martha aura dans ce cas un peu plus de contrôle au sens où c'est elle qui pourra fixer la date et c'est les jardiniers disponibles qui la contacteront. Si Pierre est disponible, il contactera sans doute Martha, sinon un autre jardinier le fera, Amed par exemple.

Ce système est mieux au sens où entre chaque taille de haie Martha peut facilement changer de jardinier, vu qu'elle va reposter une annonce à chaque fois. Mais si un jardinier s'est engagé à accomplir la tâche et que celui-ci tombe malade, le jardin de Martha devra attendre.

Sous forme d'objet on aurait toujours directement Martha, mais elle ne connaîtrait plus vraiment le jardinier, uniquement ce qu'il apporte comme compétence, ici tailler une haie.

Martha a besoin de tailler une haie

Maintenant c'est toujours à Martha de gérer les appels des jardiniers, et elle n'a aucune garantie qu'un jardinier verra son annonce. Elle pourrait donc préférer comme beaucoup d'autres gens de faire appelle à une société de service d'aide au jardinage, par exemple Jardin Cie. Une telle société servira d'intermédiaire. Martha n'aura alors plus qu'à appeler Jardin Cie qui se chargera de trouver un jardinier pour la date convenue. Par contre ici, Martha ne fait que bloquer un créneau pas un jardinier, on peut donc imaginer que Pierre avait été désigné pour aller chez Martha, mais que celui-ci tombe malade la veille de l'intervention, dans ce cas Amed peut remplacer Pierre sans que ça ne pose de problème.

Sous forme d'objet, on voit qu'il n'y a plus de connexion directe entre Martha et les jardiniers. Par contre celle-ci dépend d'une société de service en particulier.

Jardin à Dom' s'occupe de tout

À l'étape précédente, Martha doit encore être active et connaître la société Jardin à Dom' et surveiller sa haie pour que la haie soit taillée lorsque c'est nécessaire.

Imaginons que Jardin à Dom' ait un moyen de savoir quand la haie de Martha doit être taillée. Dans ce cas, Martha pourrait souscrire à un abonnement auprès de Jardin à Dom' pour la taille de haie. Et Jardin à Dom' s'occuperait de contacter Martha pour programmer des interventions, ne laissant à Martha qu'à profiter de son jardin.

Quand on passe sur des objets, on se rend compte que ni Martha ni les jardiniers n'ont de contrôle sur notre système. Seul Jardin à Dom' a le contrôle. Nous somme ici dans un cas parfait d'inversion de contrôle (Inversion of Control ou IoC).

Et dans code ?

Dans Spring ?

Basiquement Spring est un injecteur de dépendance qui fonctionne en inversion de contrôle. Chaque Controleur, Service, Repository, etc. sera identifié auprès de Spring via une annotation. Ensuite Spring fera en sorte de créer les instances nécessaires pour que le système fonctionne et que chaque élément possèdent des références vers les éléments dont il dépend. Comme Spring a le contrôle il peut d'ailleurs fournir non pas une vraie référence mais un Proxy, dont il pourra changer la cible au besoin sans que les éléments aient besoin d'en avoir conscience.

Et dans Angular ?

On retrouve le même schéma que pour Spring avec les Component, Service, Module, etc. Les annotations servent à identifier auprès d'Angular chaque élément qui sera instancié au besoin.

Une obligation de passer par des annotations ?

C'est courant, mais ce n'est pas une obligation. On trouvera aussi des systèmes qui utilisent des déclarations explicites de quelle classe il faut utiliser lorsqu'un élément du système dépend d'une interface en particulier.

Crédit photo : https://pixabay.com/photos/lawnmower-gardening-lawn-mower-384589/