Détails
Qu'est-ce que l'injection de dépendances ?
Plusieurs questions ont déjà été postées avec des questions spécifiques sur l'[injection de dépendance][1], comme quand l'utiliser et quels frameworks existent pour cela. Cependant,
Qu'est-ce que l'injection de dépendances et quand/pourquoi doit-on ou ne doit-on pas l'utiliser?
2972
3
La meilleure définition que j'ai trouvée jusqu'à présent est une définition de James Shore :
Il existe un article de Martin Fowler qui peut également s'avérer utile.
L'injection de dépendances consiste essentiellement à fournir les objets dont un objet a besoin (ses dépendances) au lieu de les lui faire construire lui-même. Il s'agit d'une technique très utile pour les tests, car elle permet de simuler les dépendances.
Les dépendances peuvent être injectées dans les objets par de nombreux moyens (comme l'injection de constructeur ou l'injection de setter). On peut même utiliser des cadres d'injection de dépendances spécialisés (par exemple Spring) pour le faire, mais ils ne sont certainement pas nécessaires. Vous n'avez pas besoin de ces frameworks pour disposer de l'injection de dépendances. Instancier et passer des objets (dépendances) explicitement est une injection tout aussi bonne que l'injection par framework.
L'injection de dépendances consiste à transmettre des dépendances à d'autres objets ou à un framework( injecteur de dépendances).
L'injection de dépendances facilite les tests. L'injection peut se faire par le biais du constructeur.
Le constructeur de
SomeClass()
est le suivant :Problème : Si
myObject
implique des tâches complexes comme l'accès au disque ou au réseau, il est difficile de faire des tests unitaires surSomeClass()
. Les programmeurs doivent simulermyObject
et peuvent intercepter l'appel à la fabrique.Solution alternative :
myObject
en tant qu'argument au constructeurmyObject
peut être passé directement ce qui facilite les tests.Il est plus difficile d'isoler les composants dans les tests unitaires sans injection de dépendances.
En 2013, lorsque j'ai écrit cette réponse, c'était un thème majeur sur le [Google Testing Blog][2]. Cela reste le plus grand avantage pour moi, car les programmeurs n'ont pas toujours besoin de la flexibilité supplémentaire dans leur conception d'exécution (par exemple, pour le localisateur de services ou des modèles similaires). Les programmeurs ont souvent besoin d'isoler les classes pendant les tests.
[1] : http://martinfowler.com/articles/injection.html#InterfaceInjection [2] : http://googletesting.blogspot.com/
L'injection de dépendances est une pratique selon laquelle les objets sont conçus de manière à recevoir des instances d'objets provenant d'autres parties du code, au lieu de les construire en interne. Cela signifie que tout objet implémentant l'interface requise par l'objet peut être remplacé sans modifier le code, ce qui simplifie les tests et améliore le découplage.
Par exemple, considérez ces clases :
Dans cet exemple, l'implémentation de
PersonService::addManager
etPersonService::removeManager
aurait besoin d'une instance duGroupMembershipService
afin de faire son travail. Sans l'injection de dépendances, la manière traditionnelle de faire cela serait d'instancier un nouveauGroupMembershipService
dans le constructeur dePersonService
et d'utiliser l'attribut de cette instance dans les deux fonctions. Cependant, si le constructeur deGroupMembershipService
requiert plusieurs choses, ou pire encore, s'il y a des "setters" d'initialisation qui doivent être appelés sur leGroupMembershipService
, le code se développe assez rapidement, et lePersonService
dépend maintenant non seulement duGroupMembershipService
mais aussi de tout ce dont dépend leGroupMembershipService
. De plus, le lien versGroupMembershipService
est codé en dur dans lePersonService
, ce qui signifie que vous ne pouvez pas "faconner" unGroupMembershipService
à des fins de test, ou pour utiliser un modèle de stratégie dans différentes parties de votre application.Avec l'injection de dépendance, au lieu d'instancier le
GroupMembershipService
dans votrePersonService
, vous pouvez soit le passer au constructeur duPersonService
, soit ajouter une propriété (getter et setter) pour définir une instance locale de celui-ci. Cela signifie que votrePersonService
n'a plus à se soucier de la façon de créer unGroupMembershipService
, il accepte simplement ceux qui lui sont donnés, et travaille avec eux. Cela signifie également que tout ce qui est une sous-classe deGroupMembershipService
, ou implémente l'interfaceGroupMembershipService
peut être "injecté" dans lePersonService
, et lePersonService
n'a pas besoin d'être informé de ce changement.