Articoli di programmazione

Inversion of Control e Dependency Injection spiegati bene

Il Design Pattern Inversion of Control permette di disaccoppiare le dipendenze tra oggetti rendendoli più indipendenti possibile. Dependency Injection è un pattern che consente di ottenere efficacemente IOC

unnamed.png
Solitamente molti fanno confusione tra IOC e Dependency Injection.
IOC, Inversion o Control, è un pattern tanto semplice quanto importante che, permette di disaccoppiare le dipendenze tra oggetti, rendendoli indipendenti, affinché sia possibile modificare una parte del software senza stravolgere le altre.
Dependency Injection è un pattern che professa l'iniezione delle dipendenze, ottenendo quindi IOC efficacemente.

Come al solito vediamo le porzioni importanti del codice e tralasciamo tutto il resto. Iniziamo a mettere a fuoco la problematica delle dipendenze.
Nel nostro caso abbiamo un oggetto FirstObject che esegue una chiamata di un metodo di SecondObject.
Per questa operazione decide di istanziarlo all'interno del metodo DoSomething():

class FirstObject
{
public void DoSomething()
{
var secondObject = new SecondObject();
secondObject.DoSomethingElse();
}

FirstObject non può operare senza SecondObject: dipende da lui, quindi SecondObject è una dipendenza di FirstObject.

Creare le dipendenze nel corpo dei metodi non è sbagliato di per sé. Può andare bene per piccoli progetti, in ambiente di Testing ed altre situazioni limitate. Quando però si deve imbastire un progetto un pochino più strutturato, conviene fare un passo avanti e cercare di disaccoppiare maggiormente gli oggetti.

Prima di tutto spostiamo la nostra dipendenza e trasformiamola in una variabile della nostra classe. Questo ci permette di chiamare i suoi metodi da ogni altro metodo di FirstObject, senza doverla istanziare in ogni metodo:

class FirstObject
{
SecondObject secondObject = new SecondObject();
public void DoSomething()
{
secondObject.DoSomethingElse();
}

A questo punto è il momento di applicare Dependency Injection e rendere FirstObject non più responsabile della creazione della sua dipendenza, facendogliela ricevere nel costruttore (in questo caso prende il nome di Constructor Injection, sì perché esistono anche Method Injection e Property Injection):

class FirstObject
{
SecondObject secondObject;
public FirstObject(SecondObject s)
{
secondObject = s;
}
public void DoSomething()
{
secondObject.DoSomethingElse();
}

Adesso non resta che completare il gioco rendendo la dipendenza generica tramite Interfaccia, in modo da supportare eventuali altri oggetti che ne applicano diverse implementazioni:

interface ISecondObject
{
void DoSomethingElse();
}
class FirstObject
{
ISecondObject secondObject;
public FirstObject(ISecondObject s)
{
secondObject = s;
}
public void DoSomething()
{
secondObject.DoSomethingElse();
}

Abbiamo ottenuto Inversion Of Control, cioè il controllo delle dipendenze è stato invertito e non è più a carico di FirstObject, tramite Dependency Injection di tipo Constructor Injection, cioè iniettiamo le dipendenze nel costruttore di FirstObject.

Nel mondo reale esistono i cosiddetti IOC Containers, come Unity, Ninject e Castle Windsor, solo per citarne alcuni, che permettono in seguito ad una configurazione iniziale di ottenere i nostri oggetti già pronti per l'utilizzo con le dipendenze già iniettate.

Vediamo un semplice esempio di uso con Unity :

IUnityContainer c = new UnityContainer();
c.RegisterType<ISecondObject, SecondObject>();
c.RegisterType<FirstObject>();
FirstObject e = c.Resolve<FirstObject>();


IN ASP.NET Core, si ha gratuitamente Dependency Injection tramite IOC Container incorporato, da configurare nel metodo ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<ISecondObject, SecondObject>();
services.AddScoped<FirstObject>();
}


#programmazione #designPatterns #IOC