2011-11-10 9 views
6

L'applicazione sto lavorando si basa su Autofac come DI contenitore e uno dei motivi che mi ha fatto decidere di usarlo, tra gli altri, è stata la caratteristica delegato di fabbrica (vedi here)Service Locator più facile da usare dell'iniezione di dipendenza?

Questo funziona bene per tutti i casi dove ho bisogno di ricreare gli stessi elementi più volte, come nel caso di alcuni report e schermate correlate. Alcuni report (anche quelli dello stesso tipo) vengono eseguiti contemporaneamente ma cambiano solo in base ai parametri definiti dall'utente, quindi ha senso (credo) inserire le factory per creare istanze, passare i parametri liberi e lasciare il resto al applicazione.

Il problema deriva dal fatto che ogni rapporto è composto da un numero variabile di sottoreti (attività) e ogni attività implementa un'interfaccia ITask. Ogni report può avere fino a 50 diverse attività da utilizzare e ogni attività incapsula un'operazione di business precisa. Una delle opzioni che ho è di iniettare le fabbriche delegate e crearle quando necessario.

Questi compiti devono essere dinamicamente generati dalle fabbriche e qualcosa come:

var myTaskA = _taskFactoryConcreteTaskA(); 
var myTaskB = _taskFactoryConcreteTaskB(); 
var myTaskC = _taskFactoryConcreteTaskC(); 
... 
var myTaskZZ = = _taskFactoryConcreteTaskZZ(); 

richiede un sacco di cablaggio manuale (delegati, il costruttore, il backup campi ecc), mentre qualcosa come

var myTaskA = _taskFactory.Create<ConcreteTaskA>(); 
var myTaskB = _taskFactory.Create<ConcreteTaskB>(); 
var myTaskC = _taskFactory.Create<ConcreteTaskC>(); 
... 
var myTaskZZ = _taskFactory.Create<ConcreteTaskZZ>(); 

sarebbe essere incredibilmente meno lavoro, specialmente se la _taskFactory esegue il wrapping del contenitore come mostrato in this other post, ma fondamentalmente significa che sto usando un localizzatore di servizi per creare i miei compiti.

Quali altre opzioni sono disponibili per risolvere questo problema?

(NOTA: c'è una buona probabilità Sono completamente fuori pista e che devo leggere molto di più su DI, nel qual caso qualsiasi contributo sarebbe ancora più importante)

+0

Martin Fowler ha scritto su questo un po ': http://martinfowler.com/articles/injection.html#UsingAServiceLocator – mwilson

+2

Grazie, questo è ciò che mi ha fatto ripensare a tale proposito l'articolo molto: http: //blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx (e mi ha convinto ad acquistare il libro, comunque lo sto aspettando) – mhttk

risposta

3

Un approccio vale la pena indagare è quello di rompere le into'units problema del lavoro' che utilizzano un insieme di attività correlate:

public class WorkItem1 : ISomeWork 
{ 
    public WorkItem1(Task1 t1, Task2 t2...) { } 
    public void DoSomething() { ... } 
} 

Quindi, l'utilizzo di fabbriche sarebbe venuto giù verso someWorkFactory().DoSomething(), forse per un paio di diversi tipi di 'qualcosa'.

Una classe con un gran numero di dipendenze, su fabbriche o qualsiasi altra cosa, di solito indica che ci sono classi più piccole e più focalizzate che aspettano di essere scoperte per interrompere il lavoro.

Spero che questo aiuti.

+0

+1 Tuttavia, vedi la mia risposta per ulteriori opzioni. –

+0

grazie, questo è interessante in quanto potrebbe effettivamente funzionare per me. il fatto di utilizzare diverse attività all'interno di una classe di report consiste nell'assegnare a ciascuna attività la risoluzione di parti specifiche di report complessi, riducendo la complessità del codice complessivo rendendolo più chiaro. magari scomposendo il report nelle sottosezioni e lasciando che le fabbriche facciano l'istanza quando necessario. – mhttk

6

Poiché gli stabilimenti indicati nella domanda non accettano argomenti, utilizza un odore di fabbrica di Leaky Abstraction. Come sottolinea Nicholas Blumhardt nella sua risposta, un approccio migliore potrebbe essere semplicemente iniettare ogni attività nel consumatore.

In questo caso, dal momento che tutte le attività implementano la stessa interfaccia, invece di iniettare fino a 50 diverse ITask casi, è possibile comporli:

public class MyConsumer 
{ 
    private readonly IEnumerable<ITask> tasks; 

    public MyConsumer(IEnumerable<ITask> tasks) 
    { 
     this.tasks = tasks; 
    } 

    public void DoSomething() 
    { 
     foreach (var t in this.tasks) 
     { 
      // Do something with each t 
     } 
    } 
} 

In alternativa, è possibile comporre la sequenza di ITasks in un Composite, che è in realtà la mia soluzione preferita:

public CompositeTask : ITask 
{ 
    private readonly IEnumerable<ITask> tasks; 

    public CompositeTask(IEnumerable<ITask> tasks) 
    { 
     this.tasks = tasks; 
    } 

    // Implement ITask by iterating over this.tasks 
} 

Ciò semplificherebbe il consumatore e ruotare il fatto che ci sono più di un compito da eseguire in un dettaglio implementativo :

public class MyConsumer 
{ 
    private readonly ITask task; 

    public MyConsumer(ITask task) 
    { 
     this.task = task; 
    } 

    public void DoSomething() 
    { 
     // Do something with this.task 
    } 
} 
+0

Grazie, ho considerato questo scenario, ma non sono sicuro di capire cosa stai suggerendo qui. Se creo un'attività composita, devo ancora iniettare un 'IEnumerable ' ma chi sta per inserire le attività corrette nella raccolta? Forse non ho spiegato il fatto che diversi report usano diversi gruppi di attività e nell'esempio che hai assunto per iniettare tutte le attività disponibili? Tuttavia, gli esempi di voi e di Nicholas Blumhardt forniscono utili informazioni, grazie. – mhttk

+2

Il compositore (la radice di composizione) prende la decisione su quali attività inserire. Mentre * è possibile * iniettare tutte le implementazioni ITask nei report * all *, è anche possibile selezionare solo un sottoinsieme per ciascun report. Quando si utilizza un contenitore DI, questa è solo una questione di configurazione del contenitore in modo corretto. –

+0

Vedo, questo è molto interessante. Questo mi fa capire cos'è che suggeriva il suggerimento di NicholasBlumhardt. Grazie. (ps sto aspettando con impazienza [questo libro] (http://manning.com/seemann/) per essere consegnato, ottimo lavoro!) – mhttk

Problemi correlati