En fait, la "bonne" façon est de ne PAS utiliser d'usine du tout, sauf s'il n'y a absolument pas d'autre choix (comme dans les tests unitaires et certaines simulations - pour le code de production, vous n'utilisez PAS d'usine)! Cela est en fait un anti-modèle et doit être évité à tout prix. Tout l'intérêt d'un conteneur DI est de permettre au gadget de faire le travail pour vous.
Comme indiqué ci-dessus dans un article précédent, vous voulez que votre gadget IoC assume la responsabilité de la création des différents objets dépendants dans votre application. Cela signifie laisser votre gadget DI créer et gérer les différentes instances lui-même. C'est tout le point derrière DI - vos objets ne doivent JAMAIS savoir comment créer et / ou gérer les objets dont ils dépendent. Pour faire autrement pauses lâche accouplement.
La conversion d'une application existante en toutes DI est une étape énorme, mais en mettant de côté les difficultés évidentes à le faire, vous voudrez également (juste pour vous faciliter la vie) explorer un outil DI qui exécutera automatiquement la majeure partie de vos liaisons (le noyau de quelque chose comme Ninject est les "kernel.Bind<someInterface>().To<someConcreteClass>()"
appels que vous faites pour faire correspondre vos déclarations d'interface aux classes concrètes que vous souhaitez utiliser pour implémenter ces interfaces. Ce sont ces appels "Bind" qui permettent à votre gadget DI d'intercepter vos appels de constructeur et de fournir les instances d'objets dépendantes nécessaires. Un constructeur typique (pseudo-code montré ici) pour une classe peut être:
public class SomeClass
{
private ISomeClassA _ClassA;
private ISomeOtherClassB _ClassB;
public SomeClass(ISomeClassA aInstanceOfA, ISomeOtherClassB aInstanceOfB)
{
if (aInstanceOfA == null)
throw new NullArgumentException();
if (aInstanceOfB == null)
throw new NullArgumentException();
_ClassA = aInstanceOfA;
_ClassB = aInstanceOfB;
}
public void DoSomething()
{
_ClassA.PerformSomeAction();
_ClassB.PerformSomeOtherActionUsingTheInstanceOfClassA(_ClassA);
}
}
Notez que nulle part dans ce code, aucun code n'a créé / géré / publié l'instance de SomeConcreteClassA ou SomeOtherConcreteClassB. En fait, aucune classe concrète n'était même référencée. Alors ... où la magie s'est-elle produite?
Dans la partie de démarrage de votre application, les événements suivants ont eu lieu (encore une fois, il s'agit d'un pseudo-code mais il est assez proche de la réalité (Ninject) ...):
public void StartUp()
{
kernel.Bind<ISomeClassA>().To<SomeConcreteClassA>();
kernel.Bind<ISomeOtherClassB>().To<SomeOtherConcreteClassB>();
}
Ce petit bout de code indique au gadget Ninject de rechercher des constructeurs, de les analyser, de rechercher des instances d'interfaces qu'il a été configuré pour gérer (c'est-à-dire les appels "Bind"), puis de créer et de remplacer une instance de la classe concrète partout où l'instance est référencée.
Il existe un bel outil qui complète très bien Ninject, appelé Ninject.Extensions.Conventions (encore un autre package NuGet) qui fera le gros de ce travail pour vous. Ne pas retirer de l'excellente expérience d'apprentissage que vous vivrez au fur et à mesure que vous la construirez, mais pour vous lancer, cela pourrait être un outil pour enquêter.
Si la mémoire est bonne, Unity (officiellement de Microsoft maintenant un projet Open Source) a un appel de méthode ou deux qui font la même chose, d'autres outils ont des assistants similaires.
Quelle que soit la voie que vous choisissez, lisez certainement le livre de Mark Seemann pour l'essentiel de votre formation en DI, cependant, il convient de souligner que même les «grands» du monde de l'ingénierie logicielle (comme Mark) peuvent faire des erreurs flagrantes - Mark a tout oublié Ninject dans son livre alors voici une autre ressource écrite juste pour Ninject. Je l'ai et c'est une bonne lecture: Mastering Ninject for Dependency Injection