In questo primo articolo darò un'introduzione "infantile" al concetto di Inversion of Control(IoC) ed ad una sua implementazione tramite il pattern di Dependency Injection(DI). Sebbene IoC e DI siano considerati sinonimi, mi è sembrato di capire che DI sia una implementazione particolare di IoC, a mano o tramite framework. Comuque, qui non farò riferimento a framework particolari, ma solo al principio di base che dovrebbe condurci a scrivere codice a basso accoppiamento (low coupling).
Per una mia innata prigrizia, mi piace di più usare le immagini per fissare i concetti. Non sto qui ad elencare i motivi biologici.
Già, chi collegherebbe una lampada saldandola ai cavi elettrici nella parete ? A patto che abbia voglia di vincere il
premio Darwin di quest'anno. Il problema è che non sono sicuro del risultato finale ...
DIP in pratica ci spinge a utilizzare e dipendere da interfacce (o astrazioni). Quasi non c'è più niente da dire, vista la banalità della cosa. Pigro sì, ma pragmatico:
- Nessuna classe dovrebbe derivare da un tipo concreto
- Nessuna variabile dovrebbe avere un riferimento ad un tipo concreto
- Nessun metodo dovrebbe fare l'override di un metodo implementato in qualcuna delle sue classi base
Altre due imaginette ci aiutano a capire ancora meglio:
Nella prima una classe consumer ha delle dipendenze con le classi concrete, ovvero ha il comp ci creare uno dei tre tipi facendo ricorso all'operatore new
E' il caso appunto in ciui componenti ad alto livello dipendono da componenti a basso livello
Il verso della dipendenza imita molto quello della tipica programmazione procederale
public class Dependent
{
public IDependent _dependent;
public void DoSomething(string dependent)
{
if (dependent.EndsWith("1"))
_dependent = new DependentClass1();
if (dependent.EndsWith("2"))
_dependent = new DependentClass2();
if (dependent.EndsWith("3"))
_dependent = new DependentClass3();
_dependent.DoSomethingInDependent();
}
}
La seconda invece ci mostra gli effetti della cura dopo aver implementato DIP:
L'iniettore della dipendenza stesso dipende da una astrazione (classe
abstract o tipo
interface). Ovvero possiede un riferimento all'interfaccia tramite un campo privato
Così i tipi concreti che derivano dall'interfaccia, implementandola
Il verso della dipendenza si è
invertita, da questo il nome di Inversione di Controllo (mesi fà mi dicevo: inversione de che ??)
public class Injector
{
private IDependent _dependent;
public IDependent Dependent
{
get { return _dependent; }
set { _dependent = value; }
}
public void DoSomething()
{
Dependent.DoSomethingInDependent();
}
}
Persino il class diagram, uhh:
Martin Fowler in suo
famosissimo articolo ci insegna 3 tipi di DI:
- Iniezione tramite metodi d'interfaccia di Tipo 1
- Iniezione tramite proprietà di Tipo 2
- Iniezione tramite costruttore di Tipo 3
La prima è quella che obbliga a definire un'interfaccia (da non confondersi con l'
astrazione necessaria al DIP) , dalla quale poi l'iniettore dovrà derivare, constringendolo ad implementare i metodi
La seconda invece è la proprietà che si preoccupa di valorizzare il campo privato che rappresenta la dipendenza verso l'interfaccia
La terza invece è quella in cui, il riferimento viene risolto nel momento in cui l'iniettore viene creato, dovendolo passare come parametro.
Forse Martin si era sparato tutti i cofanetti di Spielberg prima di scrivere l'articolo, diciamo che non farei una distinzione così ferrea tra tipi, basta capire quando ci servono.
Delle tre, la prima non l'ho mai usata nè vista usare. Dopo tutto devo scrivere del codice in più. Preferisco la seconda e la terza modalità o un misto delle due, poichè mi risulta comodo per lo "state based unit-testing", cioè posso governare e controllare come viene risolta la dipendenza. Userei solo la seconda o al massimo la prima solo quando ho bisogno di posticipare l'iniezione.
Dimenticavo, appena posso mi comprerò questa simpatica magliettina che fa parte della
campagna anti-if promossa da xplabs.
E' proprio IoC, uno dei mezzi che ci aiutano in questa battaglia. Non per
if stesso ma per un suo abuso, chiaro.
NB: ho fatto anche un versione video, o
screencast, di questo articolo. Devo un attimo sistemare il "montaggio". Ho Sergio Leone in chat che mi sta dando dei validi consigli. Lo pubblico più tardi o al max domani mattina.