2011-10-21 3 views
6

Recentemente ho chiesto di fare correttamente DI, e ho ottenuto alcuni collegamenti ai post del blog su di esso. Penso di avere una migliore comprensione ora - separare la costruzione di oggetti dalla logica, inserendola nelle fabbriche. Ma tutti gli esempi sono per cose come i siti web e dicono di fare tutto il cablaggio all'avvio. Chiama una grande fabbrica che è la new s e passa tutte le dipendenze.Quando e dove chiamare le fabbriche in fase di runtime?

Ma cosa succede se non voglio istanziare tutto in anticipo? Ho un oggetto che contiene un elenco di altri oggetti a cui è possibile delegare, ma sono costosi e usati uno alla volta, quindi li costruisco quando è necessario e li raccolgo quando ho finito. Non voglio inserire new B() nella logica di A perché preferirei usare DI - ma come? A può chiamare la fabbrica? Non sembra molto meglio, a meno che la fabbrica non mantenga lo stato, comprese le dipendenze attuali. Solo non voglio passare l'elenco completo di B s a A quando è stato costruito, poiché sarebbe uno spreco. Se si desidera, B non necessariamente devono essere dentro A, anche se ha un senso logico (A è un livello di gioco, B è un singolo schermo), ma in ogni caso la logica della A impone quando si crea B.

Quindi, chi chiama la fabbrica per ottenere B e quando?

Chiarimento: Non sto utilizzando framework per DI. Mi chiedo se il termine DI lo sottintenda?

+0

grande domanda. Sono stato anche confuso da questo problema. Inoltre, a volte voglio più istanze di qualcosa (e un numero arbitrario di esse in quel caso!) E sono stato molto confuso su come dovrebbe funzionare. Con Ninject ho appena risucchiato e iniettato 'IKernel', ma mi viene dato di capire che è disapprovato. (anche se, secondo la mia esperienza, è molto potente e devo ancora rimpiangere - e no, non sono nemmeno lontanamente interessato a "scambiare" il mio framework DI, quindi il vantaggio mi viene in mente) –

+0

E 'solo disapprovato dagli sviluppatori che avere qualche comprensione religiosa dei modelli. Anche se non andrei in giro selvaggio dove ogni tipo sa di IKernel, o qualunque sia il suo nome nel tuo framework DI, a volte questo è il modo migliore per andare. Ho fatto anche questo, e nulla è esploso su di me. – Andy

risposta

6

In Ninject, è possibile registrare Func<B> e richiedere che nel costruttore su A.

Autofac fornirà automaticamente Func<B> se B è già registrato.

Oppure, è possibile adottare un approccio più diretto e definire un factory esplicito per B e richiedere tale factory nel costruttore; è solo un po 'più digitante in quanto dovresti creare una factory per ogni dipendenza che vuoi inizializzare pigramente.


Ecco un altro SO risponde che mostra metodi di fabbrica stile Ninject: How do I handle classes with static methods with Ninject?


@Not Utilizzando Un quadro: Se è possibile, mi sarebbe probabilmente considerare di usare uno: un CIO/Di solito il framework DI gestisce la creazione ritardata per te immediatamente.

Se si desidera continuare a eseguire il rollover, passare semplicemente il factory che crea B al proprio oggetto A. Oppure, se semplicemente non ti piacciono i Func grezzi e non vuoi dover creare fabbriche esplicite per tutti i tuoi oggetti, allora puoi usare Lazy<B> per una soluzione più formalizzata.

+1

+1, ottima risposta sensata. – Andy

+0

Wow, bello! D'accordo con Andy. –

+0

La soluzione con cui sono andato non corrisponde esattamente a nessuna di queste risposte (sono andato con l'istanziazione di molte cose in anticipo), ma questo mi ha fornito alcune nuove informazioni sugli approcci di DI, quindi lo accetto. – Tesserex

1

Esistono in genere due schemi per l'utilizzo di oggetti di uso raro e costosi da creare. Il primo modello utilizza una fabbrica, come suggerisce David Faivre. L'altro è usando un proxy.

Un proxy è - da una prospettiva di progettazione - probabilmente la soluzione più pulita, anche se potrebbe richiedere più codice da implementare. È il più pulito, perché l'applicazione può essere totalmente inconsapevole di questo, perché non è necessaria un'interfaccia aggiuntiva (come l'approccio di fabbrica ha bisogno).

Ecco un semplice esempio con un po 'di interfaccia e un costoso implementazione:

interface IAmAService 
{ 
    void DoSomething(); 
} 

class ExpensiveImpl : IAmAService 
{ 
    private object x = [some expensive init]; 

    void IAmAService.DoSomething() { } 
} 

Non è possibile implementare un proxy sulla base di tale interfaccia, che possono ritardare la creazione di che l'attuazione:

class ServiceProxy : IAmAService 
{ 
    private readonly Func<IAmAService> factory; 
    private IAmAService instance; 

    public ServiceProxy(Func<IAmAService> factory) 
    { 
     this.factory = factory; 
    } 

    void IAmAService.DoSomething() 
    { 
     this.GetInstance().DoSomething(); 
    } 

    private IAmAService GetInstance() 
    { 
     // TODO: Implement double-checked lock only a single 
     // instance may exist per ServiceProxy. 
     if (this.instance == null) 
     { 
      this.instance = this.factory(); 
     } 

     return this.instance; 
    } 
} 

Questa classe proxy accetta un delegato di fabbrica come dipendenza, proprio come ha descritto David Faivre nella sua risposta, ma in questo modo l'applicazione non dovrà dipendere dallo Func<IAmAService>, ma può semplicemente dipendere da IAmAService.

Ora, invece di iniettare un ExpensiveImpl, si può iniettare un ServiceProxy in altri casi:

// Create the proxy 
IAmAService service = 
    new ServiceProxy(() => new ExpensiveImpl()); 

// Inject it into whatever you wish, such as: 
var customerService = new CustomerService(service); 
+1

+1 - Mi ha sempre infastidito il fatto che per creare una "fabbrica" ​​dovevo creare due interfacce: una per IService e una per IServiceFactory, e poi implementazioni per entrambi (questo è il motivo per cui finisco semplicemente usando Func - e perché sono pigro, probabilmente continuerà a farlo). Tuttavia, mi piace il fatto che tu stia nascondendo la fabbrica in un'implementazione diretta di IService. Ancora due implementazioni, ma ora almeno la sua unica interfaccia. Neeto. –