2010-03-26 6 views
23

Sto solo provando a riprendere i principi del CIO.IOC - Le classi di utilizzo con metodi di supporto statico devono essere cablate con IOC?

Q1: Metodi statici - Le classi di util use con metodi di supporto statico devono essere cablate con IOC?

Per esempio se ho una classe HttpUtils con un numero di metodi statici, dovrei provare a passarlo ad altre classi di business logic tramite IOC?

Segui su questioni di questo potrebbe essere:

Q2: Singletons - Che dire cose come la registrazione in cui è possibile in genere ottenere l'accesso ad essa tramite un Logger.getInstance() tipo di chiamata. Lasceresti normalmente questo così com'è, e NON usi il CIO per iniettare il logger in classi di business che ne hanno bisogno?

Q3: Classi statiche - Non ho davvero utilizzato questo concetto, ma ci sono delle linee guida su come gestirlo in genere se si stesse passando ad un approccio basato sul CIO.

Grazie in anticipo.

risposta

30

La cosa divertente di IoC è che gli oggetti scritti nello stile sono generalmente disaccoppiati da quei dettagli.

Usiamo la classe di utilità come esempio:

public class HttpUtils 
{ 
    public static void DoStuff(int someValue) 
    { 
     // ... 
    } 
} 

In un'applicazione non-IOC-focalizzato, è possibile utilizzare quel metodo direttamente:

public class Foo 
{ 
    public int Value { get; set; } 

    public void DoStuff() 
    { 
     HttpUtils.DoStuff(Value); 
    } 
} 

tuttavia, che le coppie la definizione di DoStuff direttamente alla sua implementazione. IOC si sforza di divorziare da questo tipo di dettagli, così invece si definisce l'operazione da solo:

public interface IDoesStuff 
{ 
    void DoStuff(int someValue); 
} 

Poi, lasciamo spazio a Foo per l'attuazione di cambiare:

public class Foo 
{ 
    private readonly IDoesStuff _doesStuff; 

    public Foo(IDoesStuff doesStuff) 
    { 
     _doesStuff = doesStuff; 
    } 

    public int Value { get; set; } 

    public void DoStuff() 
    { 
     _doesStuff.DoStuff(Value); 
    } 
} 

Questo disaccoppia Foo da HttpUtils. L'implementatore del concetto di DoStuff è ora un dettaglio di configurazione e non una dipendenza intrinseca (come nel caso del metodo statico).

Si noti che Foo non ha idea se il suo IDoesStuff è un singleton oppure no. Tale durata è anche un dettaglio di configurazione e non un dettaglio inerente a .

Per riassumere, IoC e static sono generalmente in disaccordo, poiché IoC promuove il cambiamento e static, per definizione, lo impedisce. Dichiara le tue dipendenze dai tuoi costruttori e scoprirai che non usi quasi mai la funzionalità static.

+0

grazie Bryan - Ciò significa che potrebbe esserci un po 'più di overhead del CIO che costruisce cose (ad esempio logger) ogni volta? Anche per le classi di tipi di utils, mi chiedo, questo renderà più difficile il refactoring mentre si refactoring le funzioni di supporto tra le classi di helper? (Sto usando ReSharper da solo) - grazie – Greg

+0

La maggior parte dei contenitori IoC consente una sorta di scoping. Con ciò intendo che si indica se il proprio oggetto viene creato ogni volta (factory), creato una volta per contesto (unità di lavoro) o una volta per applicazione (singleton). Ciò significa che è possibile registrare il registratore in modo che venga creato una sola volta. –

+2

In definitiva si desidera eliminare le classi di utilità. Ogni metodo su ciascuna di queste classi ha gli stessi problemi di accoppiamento del metodo 'HttpUtils.DoStuff' qui sopra. Per questo motivo, non si vuole richiedere che * qualsiasi * codice dipenda direttamente dai membri 'static'. Invece, prendi il corpo di 'HttpUtils.DoStuff', mettilo dietro 'IDoesStuff', ed elimina il metodo interamente da' HttpUtils'. Ora, qualsiasi classe che possa aver chiamato il metodo statico può invece accettare 'IDoesStuff' nel suo costruttore. Viola: non serve più per la classe di utilità! –

6

Un contenitore IoC è in genere utile per iniettare oggetti che hanno stato; o classi o interfacce che hanno più di una implementazione, anche se la seconda implementazione è una simulazione a scopo di test. Se nessuno di questi è vero, non ottieni nulla iniettandolo.l'idioma più comune in questi giorni è quello di far fronte alla tua classe tramite un'interfaccia che l'implementazione reale e simulata può implementare.

1) Metodi statici sulle classi di supporto - No, questi non vengono spesso iniettati da IoC. Tipicamente sono utilità stateless.

Per utilizzare un esempio molto semplice, non sono necessarie due versioni di un metodo di utilità chiamato StringUtils.Reverse(). Ne hai bisogno solo uno, e puoi facilmente scrivere dei test su di esso perché non ha stato o dipendenze, quindi non c'è assolutamente alcun vantaggio nel prenderlo in giro. Test Esempio:

string reversedString = StringUtils.Reverse("input"); 
Assert.AreEqual("tupni", reversedString) 

Se l'utilità non è davvero senza stato (ad esempio, dipende HttpContext.Current), allora si dovrebbe fare la dipendenza esplicita per iniezione, e non fare l'utilità statica.

2) Singletons: Spesso sì, vengono iniettati singleton. Ma una cosa positiva di IoC è che ti preoccupi di meno se c'è solo una cosa o meno. Ottieni flessibilità nell'istanziamento utilizzando IoC. La decisione di avere un tipo particolare come singleton o nuova istanza ogni volta diventa parte della configurazione del contenitore IoC e nient'altro nel codice deve essere modificato.

Quindi il singleton-cappa smette di essere un problema separato che deve essere codificato nella classe (e le classi che hanno più problemi quando non devono necessariamente è cattivo), e diventa la preoccupazione del contenitore IoC. Non codifichi la classe "come un singleton" con qualcosa di speciale come un costruttore privato e un metodo , basta codificarlo per il problema principale, mentre la configurazione del contenitore IoC specifica se è un singleton o no, o da qualche parte in mezzo, come un'istanza per thread.

3) Classi statiche - sono la sede naturale per i metodi statici. Prendi in considerazione l'idea di rendere i metodi di estensione dei metodi statici, ove appropriato. Non è possibile iniettare queste classi, poiché non è possibile crearle. L'uso di classi statiche rende il codice procedurale non orientato agli oggetti. Questa non è una brutta cosa per i piccoli metodi di supporto, ma se la maggior parte del codice è così, allora non stai usando le potenti funzionalità OO della piattaforma .Net.

2

I metodi statici per definizione non richiedono un'istanza. DI/IOC ha lo scopo di soddisfare le interfacce con classi concrete e dato che la tua classe statica insieme ai suoi metodi statici per definizione non può implementare un'interfaccia o estendere una classe, la domanda non ha senso. Non ha senso passare la classe helper perché non è necessario che l'istanza utilizzi i metodi statici. Il codice eseguirà sempre gli stessi metodi di helperr statico anche senza un'istanza.

In un'applicazione basata su IOC/DI si definiscono le interfacce e si ha almeno un'implementazione. Si tratta di gestire le istanze e le loro dipendenze.

0

Il dilemma sorge quando le classi di utilità, ad esempio, richiedono un database di accesso. Sebbene l'accesso db abbia bisogno di Ioc, la classe di utilità deve utilizzare Ioc come, quindi non può essere statica.

Ma io voglio davvero che la classe di utilità sia statica, così facile da essere consumata. Non voglio popolare il costruttore di ogni classe di consumi che ha bisogno di classi di utilità.

Le classi di consumo potrebbero non richiedere nemmeno l'accesso al db. Quindi non voglio iniettare db accessor e passarlo anche nelle classi di utilità.

Indovina che non esiste una soluzione perfetta per ora.Un giorno spero che faremo un ulteriore passo in avanti, oltre all'iniezione costruttore/proprietà, che ci sia "iniezione/configurazione del contesto globale", o "iniezione statica", applicare Ioc oltre la creazione dell'oggetto.

Pensa, perché no?

+0

Questa è una risposta o solo un commento sulla domanda? –