La gestione del ciclo di vita delle dipendenze è l'organizzazione della creazione, inizializzazione, aggiornamento e distruzione dei componenti dell'applicazione in modo che siano indipendenti l'uno dall'altro e facilmente testabili. A tal fine si utilizzano spesso contenitori IoC (Inversion of Control) e il pattern Dependency Injection (DI).
Contenitore IoC consente:
Esempio in C# utilizzando Microsoft.Extensions.DependencyInjection:
public interface IMessageSender { void Send(string msg); } public class EmailSender : IMessageSender { public void Send(string msg) { /* invia email */ } } // Registrazione delle dipendenze var services = new ServiceCollection(); services.AddScoped<IMessageSender, EmailSender>(); // Ottenere un'istanza var provider = services.BuildServiceProvider(); var sender = provider.GetService<IMessageSender>(); sender.Send("Ciao!");
Caratteristiche principali:
Qual è la differenza tra l'iniezione delle dipendenze (DI) e il pattern Service Locator, e perché il Service Locator è considerato un antipattern?
Il Service Locator viola la chiara trasmissione delle dipendenze, rendendo il codice meno trasparente. È meglio utilizzare DI tramite costruttori o metodi in modo che il compilatore controlli la correttezza delle dipendenze.
// Male: Service Locator var sender = ServiceLocator.Get<IMessageSender>(); // Bene: tramite DI public class MyService { public MyService(IMessageSender sender) { ... } }
Qual è la differenza tra il pattern Singleton e il tempo di vita Single Instance nel contenitore DI?
Il pattern Singleton è implementato manualmente e non dipende dal contenitore; Single Instance fornisce un'istanza dal contenitore, il che è più sicuro per i test unitari e per l'estensione.
È necessario iniettare dipendenze in tutte le classi, anche nelle semplici utility?
No. Non ha senso iniettare DI in utility senza dipendenze o classi helper debolmente collegate (ad esempio, una classe di costanti matematiche) — questo complica il codice senza apportare benefici.