Je m'excuse si cela semble être une autre répétition de la question, mais chaque fois que je trouve un article sur le sujet, il parle principalement de ce qu'est DI. Donc, je reçois DI, mais j'essaie de comprendre le besoin d'un conteneur IoC, dans lequel tout le monde semble se lancer. Le but d'un conteneur IoC est-il vraiment juste de "résoudre automatiquement" l'implémentation concrète des dépendances? Peut-être que mes classes ont tendance à ne pas avoir plusieurs dépendances et c'est peut-être pourquoi je ne vois pas le problème, mais je veux m'assurer que je comprends correctement l'utilité du conteneur.
Je divise généralement ma logique métier en une classe qui pourrait ressembler à ceci:
public class SomeBusinessOperation
{
private readonly IDataRepository _repository;
public SomeBusinessOperation(IDataRespository repository = null)
{
_repository = repository ?? new ConcreteRepository();
}
public SomeType Run(SomeRequestType request)
{
// do work...
var results = _repository.GetThings(request);
return results;
}
}
Il n'a donc qu'une seule dépendance, et dans certains cas, il peut en avoir une deuxième ou une troisième, mais pas souvent. Donc, tout ce qui appelle cela peut passer son propre référentiel ou lui permettre d'utiliser le référentiel par défaut.
En ce qui concerne ma compréhension actuelle d'un conteneur IoC, tout ce que fait le conteneur est de résoudre IDataRepository. Mais si c'est tout ce qu'il fait, alors je n'y vois pas une tonne de valeur car mes classes opérationnelles définissent déjà un repli lorsqu'aucune dépendance n'est passée. Donc, le seul autre avantage auquel je peux penser est que si j'ai plusieurs opérations comme ceci utilise le même dépôt de secours, je peux changer ce dépôt en un seul endroit qui est le registre / usine / conteneur. Et c'est très bien, mais c'est tout?
la source
ConcreteRepository
et (2) vous pouvez fournir des dépendances supplémentaires àConcreteRepository
(une connexion à la base de données serait courante, par exemple).Réponses:
Le conteneur IoC ne concerne pas le cas où vous avez une dépendance. Il s'agit du cas où vous avez 3 dépendances et elles ont plusieurs dépendances qui ont des dépendances, etc.
Il vous aide également à centraliser la résolution d'une dépendance et la gestion du cycle de vie des dépendances.
la source
Il existe un certain nombre de raisons pour lesquelles vous souhaiterez peut-être utiliser un conteneur IoC.
DLL non référencées
Vous pouvez utiliser un conteneur IoC pour résoudre une classe concrète à partir d'une DLL non référencée. Cela signifie que vous pouvez prendre des dépendances entièrement sur l'abstraction - c'est-à-dire l'interface.
Évitez l'utilisation de
new
Un conteneur IoC signifie que vous pouvez supprimer complètement l'utilisation du
new
mot - clé pour créer une classe. Cela a deux effets. Le premier est qu'il dissocie vos classes. La seconde (qui est liée) est que vous pouvez déposer des simulations pour les tests unitaires. C'est incroyablement utile, en particulier lorsque vous interagissez avec un long processus.Écrivez contre les abstractions
L'utilisation d'un conteneur IoC pour résoudre vos dépendances concrètes vous permet d'écrire votre code contre des abstractions, plutôt que d'implémenter chaque classe concrète dont vous avez besoin selon vos besoins. Par exemple, vous pourriez avoir besoin de votre code pour lire les données d'une base de données. Au lieu d'écrire la classe d'interaction de la base de données, vous écrivez simplement une interface pour elle et vous codez par rapport à cela. Vous pouvez utiliser une maquette pour tester la fonctionnalité du code que vous développez au fur et à mesure que vous le développez, plutôt que de compter sur le développement de la classe d'interaction de base de données concrète avant de pouvoir tester l'autre code.
Évitez le code fragile
Une autre raison d'utiliser un conteneur IoC est qu'en s'appuyant sur le conteneur IoC pour résoudre vos dépendances, vous évitez de devoir changer chaque appel à un constructeur de classe lorsque vous ajoutez ou supprimez une dépendance. Le conteneur IoC résoudra automatiquement vos dépendances. Ce n'est pas un problème énorme lorsque vous créez une classe une fois, mais c'est un problème gigantesque lorsque vous créez la classe dans une centaine d'endroits.
Gestion à vie et nettoyage non géré des ressources
La dernière raison que je mentionnerai est la gestion des durées de vie des objets. Les conteneurs IoC offrent souvent la possibilité de spécifier la durée de vie d'un objet. Il est très logique de spécifier la durée de vie d'un objet dans un conteneur IoC plutôt que d'essayer de le gérer manuellement dans le code. La gestion manuelle de la durée de vie peut être très difficile. Cela peut être utile lorsque vous traitez des objets qui doivent être éliminés. Au lieu de gérer manuellement l'élimination de vos objets, certains conteneurs IoC géreront l'élimination pour vous, ce qui peut aider à prévenir les fuites de mémoire et à simplifier votre base de code.
Le problème avec l'exemple de code que vous avez fourni est que la classe que vous écrivez a une dépendance concrète sur la classe ConcreteRepository. Un conteneur IoC supprimerait cette dépendance.
la source
Selon le principe de la responsabilité unique, chaque classe ne doit avoir qu'une seule responsabilité. La création de nouvelles instances de classes n'est qu'une autre responsabilité, vous devez donc encapsuler ce type de code dans une ou plusieurs classes. Vous pouvez le faire en utilisant n'importe quel modèle de création, par exemple des usines, des constructeurs, des conteneurs DI, etc.
Il existe d'autres principes comme l'inversion de contrôle et l'inversion de dépendance. Dans ce contexte, elles sont liées à l'instanciation des dépendances. Ils indiquent que les classes de haut niveau doivent être découplées des classes de bas niveau (dépendances) qu'elles utilisent. Nous pouvons découpler les choses en créant des interfaces. Les classes de bas niveau doivent donc implémenter des interfaces spécifiques et les classes de haut niveau doivent utiliser des instances de classes qui implémentent ces interfaces. (Remarque: la contrainte d'interface uniforme REST applique la même approche au niveau du système.)
La combinaison de ces principes par l'exemple (désolé pour le code de faible qualité, j'ai utilisé un langage ad hoc au lieu de C #, car je ne le sais pas):
Pas de SRP, pas d'IoC
Plus proche de SRP, pas d'IoC
Oui SRP, non IoC
Oui SRP, oui IoC
Nous avons donc fini par avoir un code dans lequel vous pouvez remplacer chaque implémentation concrète par une autre qui implémente la même interface ofc. C'est donc bien car les classes participantes sont découplées les unes des autres, elles ne connaissent que les interfaces. Autre avantage que le code de l'instanciation est réutilisable.
la source