Ho letto con interesse questo articolo che afferma:
A DI Container should only be referenced from the Composition Root. All other modules should have no reference to the container.
This means that all the application code relies solely on Constructor Injection (or other injection patterns), but is never composed. Only at the entry point of the application is the entire object graph finally composed.
Prendo per significare che tutte le istanze dovrebbero essere iniettate, mai istanziate da qualcosa di diverso dal contenitore IoC.
Sotto questo modello, questo non è permesso:
class MyClass {
void SomeMethod() {
var w = new Worker();
w.DoSomething();
}
}
Invece dovrebbe assomigliare più a questo:
class MyClass {
protected readonly IWorker _worker;
public MyClass(IWorker worker) {
_worker = worker;
}
void SomeMethod() {
_worker.DoSomething();
}
}
Funziona bene se ho solo bisogno di un'istanza di Worker
per istanza di MyClass
. Ma cosa succede se Worker
è stateful (o peggio, usa e getta) e ho bisogno di una nuova istanza ogni volta che si chiama SomeMethod
?
Potrei fare qualcosa di simile:
class MyClass {
protected readonly IUnityContainer _container;
public MyClass(IUnityContainer container) {
_container = container;
}
void SomeMethod() {
using (var w = _container.Resolve<IWorker>()) {
w.DoSomething();
}
}
}
Ma questa tecnica è disapprovata da questo articolo , e inoltre viola il principio che il contenitore dovrebbe essere referenziato dalla radice della composizione.
Potrei iniettare una fabbrica:
class MyClass {
protected readonly IWorkerFactory _factory;
public MyClass(IWorkerFactor factory) {
_factory = factory;
}
void SomeMethod() {
using (var w = _factory.Create<IWorker>()) {
w.DoSomething();
}
}
}
... che sembra affrontare il problema. Ma poi quando vado a scrivere la fabbrica, devo fare nuovamente riferimento al contenitore:
class WorkerFactory : IWorkerFactory
{
protected readonly IUnityContainer _container;
public WorkerFactory(IUnityContainer container) {
_container = container;
}
public T Create<T>() where T : IWorker {
return _container.Resolve<T>();
}
}
... così davvero, a quanto pare, ho spostato il problema, non risolto.
Se è vero che "Un contenitore DI dovrebbe essere referenziato solo dalla radice di composizione", non vedo come sia possibile per l'istanza di chiamata per metodo.
Come posso supportare l'istanza di chiamata per metodo senza fare riferimento al contenitore al di fuori della composizione della radice?