Considérer:
public class CtorInjectionExample
{
public CtorInjectionExample(ISomeRepository SomeRepositoryIn, IOtherRepository OtherRepositoryIn)
{
this._someRepository = SomeRepositoryIn;
this._otherRepository = OtherRepositoryIn;
}
public void SomeMethod()
{
//use this._someRepository
}
public void OtherMethod()
{
//use this._otherRepository
}
}
contre:
public class MethodInjectionExample
{
public MethodInjectionExample()
{
}
public void SomeMethod(ISomeRepository SomeRepositoryIn)
{
//use SomeRepositoryIn
}
public void OtherMethod(IOtherRepository OtherRepositoryIn)
{
//use OtherRepositoryIn
}
}
Bien que l'injection de Ctor rend l'extension difficile (tout code appelant le ctor devra être mis à jour lorsque de nouvelles dépendances sont ajoutées), et l'injection au niveau de la méthode semble rester plus encapsulée à partir de la dépendance au niveau de la classe et je ne trouve aucun autre argument pour / contre ces approches .
Existe-t-il une approche définitive à adopter pour l'injection?
(NB: j'ai cherché des informations à ce sujet et j'ai essayé de rendre cette question objective.)
design-patterns
programming-practices
dependency-injection
patterns-and-practices
StuperUser
la source
la source
Réponses:
Cela dépend, si l'objet injecté est utilisé par plus d'une méthode dans la classe et que l'injection dans chaque méthode n'a pas de sens, vous devez résoudre les dépendances pour chaque appel de méthode, mais si la dépendance n'est utilisée que par une méthode qui y est injectée sur le constructeur n'est pas bonne, mais puisque vous allouez des ressources qui ne pourront jamais être utilisées.
la source
Bon, tout d'abord, parlons de "Tout code appelant le ctor devra être mis à jour lorsque de nouvelles dépendances seront ajoutées"; Pour être clair, si vous faites une injection de dépendance et que vous avez du code appelant new () sur un objet avec des dépendances, vous le faites mal .
Votre conteneur DI doit pouvoir injecter toutes les dépendances pertinentes, vous n'avez donc pas à vous soucier de changer la signature du constructeur, afin que cet argument ne tienne pas vraiment.
Quant à l'idée d'injection par méthode vs par classe, il y a deux problèmes majeurs avec l'injection par méthode.
Un problème est que les méthodes de votre classe doivent partager les dépendances, c'est une façon de vous assurer que vos classes sont séparées efficacement, si vous voyez une classe avec un grand nombre de dépendances (probablement plus de 4-5), alors cette classe est un candidat de choix pour refactoring en deux classes.
Le problème suivant est que pour «injecter» les dépendances, par méthode, vous devez les transmettre à l'appel de méthode. Cela signifie que vous devrez résoudre les dépendances avant l'appel de méthode, vous vous retrouverez donc probablement avec un tas de code comme celui-ci:
Maintenant, disons que vous allez appeler cette méthode à 10 endroits autour de votre application: vous aurez 10 de ces extraits. Ensuite, disons que vous devez ajouter une autre dépendance à DoStuff (): vous devrez modifier cet extrait 10 fois (ou l'encapsuler dans une méthode, auquel cas vous ne faites que répliquer le comportement DI manuellement, ce qui est un gaspillage de temps).
Donc, ce que vous avez fait là-bas, c'est que vos classes utilisant DI sont conscientes de leur propre conteneur DI, ce qui est fondamentalement une mauvaise idée , car cela conduit très rapidement à une conception maladroite difficile à maintenir.
Comparez cela à l'injection de constructeur; Dans l'injection de constructeur, vous n'êtes pas lié à un conteneur DI particulier, et vous n'êtes jamais directement responsable de remplir les dépendances de vos classes, donc la maintenance est assez sans maux de tête.
Il me semble que vous essayez d'appliquer IoC à une classe contenant un tas de méthodes d'assistance non liées, alors que vous feriez mieux de diviser la classe d'assistance en un certain nombre de classes de service en fonction de l'utilisation, puis d'utiliser l'aide pour déléguer la appels. Ce n'est toujours pas une excellente approche (une aide classée avec des méthodes qui font quelque chose de plus complexe que de simplement traiter les arguments qui leur sont transmis ne sont généralement que des classes de service mal écrites), mais cela gardera au moins votre conception un peu plus propre .
(NB j'ai fait l'approche que vous proposez avant, et c'était une très mauvaise idée que je n'ai pas répétée depuis. Il s'est avéré que j'essayais de séparer les classes qui n'avaient vraiment pas besoin d'être séparées, et j'ai fini par avec un ensemble d'interfaces où chaque appel de méthode nécessitait une sélection presque fixe d'autres interfaces. C'était un cauchemar à entretenir.)
la source
"if you're doing dependency injection and you have any code calling new() on an object with dependencies, you're doing it wrong."
Si vous testez une méthode sur une classe, vous devez l'instancier ou utilisez-vous DI pour instancier votre code sous test?"any code calling the ctor will need updating"
, mon code de production n'appelle pas les ctors. Pour ces raisons.Il existe différents types d' inversion de contrôle , et votre question n'en propose que deux (vous pouvez également utiliser l'usine pour injecter la dépendance).
La réponse est: cela dépend du besoin. Parfois, il vaut mieux utiliser un type et un autre type différent.
Personnellement, j'aime les injecteurs constructeurs, car le constructeur est là pour initialiser complètement l'objet. Devoir appeler un setter plus tard rend l'objet pas entièrement construit.
la source
Vous avez manqué celui qui, au moins pour moi, est l'injection de propriété la plus flexible. J'utilise Castle / Windsor et tout ce que je dois faire est d'ajouter une nouvelle propriété auto à ma classe et j'obtiens l'objet injecté sans aucun problème et sans casser aucune interface.
la source