Champ
@Autowired
private DependencyA dependanceA;
@Autowired
private DependencyB dependanceB;
@Autowired
private DependencyC dependanceC;
Qu'est-ce qui ne va pas ? Comme vous pouvez le constater, la variante Champ est très agréable. Elle est très courte, concise, il n'y a pas de code redondant. Le code est facile à lire et à naviguer. Votre classe peut simplement se concentrer sur l'essentiel et n'est pas polluée par le code redondant de l'injection de dépendances. Vous n'avez qu'à placer l'annotation @Autowired au-dessus des champs et c'est tout. Pas besoin de constructeurs spéciaux ou de setters juste pour que le conteneur d'injection de dépendances fournisse vos dépendances. Java étant déjà verbeux, chaque opportunité de raccourcir votre code est la bienvenue, n'est-ce pas ?
Violation du principe de responsabilité unique
Il est très facile d'ajouter de nouvelles dépendances. Peut-être trop facile. Il n'y a pas de problème à ajouter six, dix ou même une douzaine de dépendances. Lorsque vous utilisez des constructeurs pour l'injection de dépendances, à un certain point, le nombre de paramètres du constructeur devient trop élevé et il est immédiatement évident qu'il y a un problème. Avoir trop de dépendances signifie généralement que la classe a trop de responsabilités. Cela peut constituer une violation du principe de responsabilité unique et de la séparation des préoccupations, et c'est un bon indicateur que la classe nécessite une inspection approfondie et éventuellement une refonte. Il n'y a pas de tel avertissement lorsque l'injection se fait directement dans les champs, car cette approche peut être mise à l'échelle indéfiniment.
Masquage des dépendances
L'utilisation d'un conteneur d'injection de dépendances signifie que la classe n'est plus responsable de la gestion de ses propres dépendances. La responsabilité d'obtenir les dépendances est extraite de la classe. Quelqu'un d'autre est désormais responsable de fournir les dépendances - le conteneur d'injection de dépendances ou les affecter manuellement dans les tests. Lorsque la classe n'est plus responsable de l'obtention de ses dépendances, elle doit les communiquer clairement en utilisant une interface publique - des méthodes ou des constructeurs. De cette manière, il est clair de ce dont la classe a besoin et aussi si c'est optionnel (setters) ou obligatoire (constructeurs).
Accouplement au conteneur d'injection de dépendances
Une des idées centrales des frameworks d'injection de dépendances est que la classe gérée ne doit pas dépendre du conteneur d'injection de dépendances utilisé. En d'autres termes, elle devrait être juste un POJO simple, qui peut être instancié indépendamment, à condition que vous lui passiez toutes les dépendances requises. De cette manière, vous pouvez l'instancier dans un test unitaire sans démarrer le conteneur d'injection de dépendances et le tester séparément (avec un conteneur, ce serait plus un test d'intégration). S'il n'y a pas d'accouplement au conteneur, vous pouvez utiliser la classe soit comme gérée, soit comme non-gérée, voire passer à un nouveau framework d'injection de dépendances.
Cependant, lors de l'injection directe dans les champs, vous ne fournissez aucun moyen direct d'instancier la classe avec toutes ses dépendances requises. Cela signifie :
Il y a un moyen (en appelant le constructeur par défaut) de créer un objet en utilisant new dans un état où il lui manque certains de ses collaborateurs obligatoires et son utilisation entraînera la NullPointerException
. Une telle classe ne peut pas être réutilisée en dehors des conteneurs d'injection de dépendances (tests, autres modules), car il n'y a aucun moyen, sauf la réflexion, de lui fournir ses dépendances requises. Immutabilité Contrairement au constructeur, l'injection de champ ne peut pas être utilisée pour attribuer des dépendances à des champs finals, rendant ainsi vos objets mutables.
3 votes
Si l'injection de champ est aussi mauvaise que vous le décrivez, pourquoi Spring la permet-elle? L'injection de champ a ses propres avantages, en rendant le code plus lisible et moins verbeux. Si vous êtes assez discipliné dans votre codage, vous pouvez être sûr que les choses ne se casseront pas même si vous utilisez l'injection de champ.
2 votes
@ashes Parce que c'était une fonctionnalité intéressante à l'époque, et les implications n'avaient pas été entièrement réfléchies. La même raison pour laquelle
Date(int, int, int)
existe.