In realtà, il modo "giusto" è di NON usare affatto una fabbrica a meno che non ci sia assolutamente altra scelta (come nei test unitari e in alcuni derisione - per il codice di produzione NON si utilizza una fabbrica)! Farlo è in realtà un anti-schema e dovrebbe essere evitato a tutti i costi. L'intero punto dietro un contenitore DI è consentire al gadget di fare il lavoro per te.
Come indicato in precedenza in un post precedente, vuoi che il tuo gadget IoC si assuma la responsabilità della creazione dei vari oggetti dipendenti nella tua app. Ciò significa consentire al tuo gadget DI di creare e gestire le varie istanze stesse. Questo è il punto alla base di DI: i tuoi oggetti non dovrebbero MAI sapere come creare e / o gestire gli oggetti da cui dipendono. In caso contrario si rompe l' accoppiamento lento.
La conversione di un'applicazione esistente in tutti i DI è un grande passo, ma mettendo da parte le ovvie difficoltà nel farlo, vorrai anche (solo per semplificarti un po 'la vita) esplorare uno strumento DI che eseguirà automaticamente la maggior parte dei tuoi binding (il nucleo di qualcosa come Ninject sono le "kernel.Bind<someInterface>().To<someConcreteClass>()"
chiamate che fai per abbinare le dichiarazioni della tua interfaccia a quelle classi concrete che desideri utilizzare per implementare quelle interfacce. Sono quelle chiamate "Bind" che consentono al tuo gadget DI di intercettare le tue chiamate del costruttore e fornire il istanze di oggetti dipendenti necessarie Un tipico costruttore (codice pseudo mostrato qui) per alcune classi potrebbe essere:
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);
}
}
Si noti che nessuna parte in quel codice era alcun codice che ha creato / gestito / rilasciato sia l'istanza di SomeConcreteClassA o SomeOtherConcreteClassB. È un dato di fatto, né a nessuna classe concreta è stato neppure fatto riferimento. Quindi ... dove è avvenuta la magia?
Nella parte di avvio della tua app, si è verificato quanto segue (di nuovo, questo è pseudo codice ma è abbastanza vicino alla cosa reale (Ninject) ...):
public void StartUp()
{
kernel.Bind<ISomeClassA>().To<SomeConcreteClassA>();
kernel.Bind<ISomeOtherClassB>().To<SomeOtherConcreteClassB>();
}
Quel po 'di codice lì dice al gadget Ninject di cercare costruttori, scansionarli, cercare istanze di interfacce che è stato configurato per gestire (cioè le chiamate "Bind") e quindi creare e sostituire un'istanza della classe concreta ovunque si fa riferimento all'istanza.
Esiste un ottimo strumento che completa Ninject molto bene chiamato Ninject.Extensions.Conventions (l'ennesimo pacchetto NuGet) che farà la maggior parte di questo lavoro per te. Non per toglierti l'eccellente esperienza di apprendimento che attraverserai mentre lo costruisci da solo, ma per iniziare, questo potrebbe essere uno strumento per indagare.
Se la memoria serve, Unity (formalmente da Microsoft ora un progetto Open Source) ha una chiamata al metodo o due che fanno la stessa cosa, altri strumenti hanno aiutanti simili.
Qualunque sia il percorso che scegli, leggi sicuramente il libro di Mark Seemann per la maggior parte della tua formazione DI, tuttavia, va sottolineato che anche i "Grandi" del mondo dell'ingegneria del software (come Mark) possono fare errori evidenti - Mark ha dimenticato tutto Ninject nel suo libro, quindi ecco un'altra risorsa scritta solo per Ninject. Ce l' ho ed è una buona lettura: Mastering Ninject per Dependency Injection