Je trouve que mes constructeurs commencent à ressembler à ceci:
public MyClass(Container con, SomeClass1 obj1, SomeClass2, obj2.... )
avec une liste de paramètres toujours croissante. Puisque "Container" est mon conteneur d'injection de dépendances, pourquoi ne puis-je pas simplement faire ceci:
public MyClass(Container con)
pour chaque classe? Quels sont les inconvénients? Si je fais cela, j'ai l'impression d'utiliser une statique glorifiée. Veuillez partager vos réflexions sur l'IoC et la folie de l'injection de dépendance.
c#
java
dependency-injection
inversion-of-control
ioc-container
JP Richardson
la source
la source
Réponses:
Vous avez raison de dire que si vous utilisez le conteneur comme localisateur de service, c'est plus ou moins une fabrique statique glorifiée. Pour de nombreuses raisons, je considère cela comme un anti-modèle .
L'un des merveilleux avantages de Constructor Injection est qu'il rend les violations du principe de responsabilité unique manifestement évidentes.
Lorsque cela se produit, il est temps de refactoriser les services de façade . En bref, créez une nouvelle interface plus grossière qui masque l'interaction entre certaines ou toutes les dépendances fines dont vous avez actuellement besoin.
la source
Je ne pense pas que vos constructeurs de classe devraient avoir une référence à votre période de conteneur IOC. Cela représente une dépendance inutile entre votre classe et le conteneur (le type de dépendance qu'IOC essaie d'éviter!).
la source
MyClass myClass = new MyClass(IDependency1 interface1, IDependency2 interface2)
(paramètres d'interface). Ceci n'est pas lié au post de @ derivation, que j'interprète comme disant qu'un conteneur d'injection de dépendance ne devrait pas s'injecter dans ses objets, c'est-à-direMyClass myClass = new MyClass(this)
La difficulté de passer les paramètres n'est pas le problème. Le problème est que votre classe en fait trop et devrait être décomposée davantage.
L'injection de dépendance peut servir d'alerte précoce pour les classes devenant trop grandes, en particulier en raison de la douleur croissante de passer dans toutes les dépendances.
la source
Je suis tombé sur une question similaire à propos de l'injection de dépendances basée sur les constructeurs et à quel point il était difficile de passer dans toutes les dépendances.
L'une des approches que j'ai utilisées dans le passé consiste à utiliser le modèle de façade d'application à l'aide d'une couche de service. Cela aurait une API grossière. Si ce service dépend de référentiels, il utiliserait une injection de setter des propriétés privées. Cela nécessite de créer une usine abstraite et de déplacer la logique de création des référentiels dans une usine.
Le code détaillé avec explication peut être trouvé ici
Meilleures pratiques pour l'IoC dans la couche de service complexe
la source
J'ai lu tout ce fil, deux fois, et je pense que les gens répondent par ce qu'ils savent, pas par ce qui est demandé.
La question d'origine de JP semble être la construction d'objets en envoyant un résolveur, puis un tas de classes, mais nous supposons que ces classes / objets sont eux-mêmes des services, mûrs pour l'injection. Et s'ils ne le sont pas?
JP, si vous cherchez à tirer parti de la DI et que vous désirez la gloire de mélanger l'injection avec des données contextuelles, aucun de ces modèles (ou supposés "anti-modèles") ne traite spécifiquement de cela. Cela revient en fait à utiliser un package qui vous soutiendra dans une telle entreprise.
... ce format est rarement pris en charge. Je crois que la difficulté de programmer un tel support, ajoutée aux performances misérables qui seraient associées à la mise en œuvre, le rend peu attrayant pour les développeurs open source.
Mais cela devrait être fait, car je devrais pouvoir créer et enregistrer une usine pour MyClass'es, et cette usine devrait pouvoir recevoir des données / entrées qui ne sont pas poussées à devenir un "service" juste pour le plaisir de passer Les données. Si «l'anti-modèle» concerne des conséquences négatives, alors forcer l'existence de types de services artificiels pour transmettre des données / modèles est certainement négatif (comparable à votre sentiment de regrouper vos classes dans un conteneur. Le même instinct s'applique).
Il y a un cadre qui peut aider, même s'il a l'air un peu moche. Par exemple, Ninject:
Création d'une instance à l'aide de Ninject avec des paramètres supplémentaires dans le constructeur
C'est pour .NET, est populaire et n'est toujours pas aussi propre qu'il devrait l'être, mais je suis sûr qu'il y a quelque chose dans la langue que vous choisissez d'utiliser.
la source
L'injection du conteneur est un raccourci que vous regretterez finalement.
La surinjection n'est pas le problème, elle est généralement le symptôme d'autres défauts structurels, notamment la séparation des préoccupations. Ce n'est pas un problème, mais il peut avoir de nombreuses sources et ce qui rend cela si difficile à résoudre, c'est que vous devrez les traiter tous, parfois en même temps (pensez à démêler les spaghettis).
Voici une liste incomplète des choses à surveiller
Mauvaise conception de domaine (racine agrégée…. Etc.)
Mauvaise séparation des préoccupations (composition du service, commandes, requêtes) Voir CQRS et Event Sourcing.
OU Mappeurs (attention, ces choses peuvent vous causer des ennuis)
Afficher les modèles et autres DTO (ne jamais en réutiliser un et essayer de les garder au minimum !!!!)
la source
Problème:
1) Constructeur avec une liste de paramètres toujours croissante.
2) Si la classe est héritée (Ex
RepositoryBase
:), la modification de la signature du constructeur entraîne la modification des classes dérivées.Solution 1
Passer
IoC Container
au constructeurPourquoi
Pourquoi pas
Solution 2
Créez une classe qui regroupe tous les services et passez-la au constructeur
Classe dérivée
Pourquoi
A
dépend, cette information est accumulée dansA.Dependency
Pourquoi pas
X.Dependency
séparément)IoC Container
La solution 2 n'est cependant qu'une solution brute, s'il existe un argument solide contre elle, un commentaire descriptif serait apprécié
la source
C'est l'approche que j'utilise
Voici une approche grossière pour effectuer les injections et exécuter le constructeur après avoir injecté des valeurs. Il s'agit d'un programme entièrement fonctionnel.
Je travaille actuellement sur un projet de passe-temps qui fonctionne comme ceci https://github.com/Jokine/ToolProject/tree/Core
la source
Quel cadre d'injection de dépendance utilisez-vous? Avez-vous plutôt essayé d'utiliser l'injection basée sur setter?
L'avantage de l'injection basée sur le constructeur est qu'il semble naturel pour les programmeurs Java qui n'utilisent pas de frameworks DI. Vous avez besoin de 5 choses pour initialiser une classe, puis vous avez 5 arguments pour votre constructeur. L'inconvénient est ce que vous avez remarqué, cela devient difficile à gérer lorsque vous avez beaucoup de dépendances.
Avec Spring, vous pouvez transmettre les valeurs requises aux setters à la place et vous pouvez utiliser les annotations @required pour faire en sorte qu'elles soient injectées. L'inconvénient est que vous devez déplacer le code d'initialisation du constructeur vers une autre méthode et demander à Spring d'appeler après toutes les dépendances en le marquant avec @PostConstruct. Je ne suis pas sûr des autres cadres mais je suppose qu'ils font quelque chose de similaire.
Les deux méthodes fonctionnent, c'est une question de préférence.
la source