L'approccio generale a DI che vedo in risposte come So Singletons sono cattivi, allora cosa? incoraggia oggetti di business che collaborano con altri oggetti a (a) no creare direttamente tali istanze e (b) farle approvare a costruzione. Posso capire (a), ma non (b). Questo sembra accadere il più delle volte in risposta a un uso eccessivo di Singletons. Ma perché non basta un approccio modificato a singleton:
class SingleInstance {
virtual foo();
virtual bar();
static SingleInstance getInstance() {
if(instance_ == null) {
instance_ = new SingleInstance();
}
return instance_;
}
void setMockInstance(SingleInstance s) {
assert(instance_ == null);
instance_ = s;
}
static SingleInstance instance_;
}
Quindi ora questo non è più Singleton con la maiuscola S (per Misko Hevery) ma in questo caso applica ancora un'istanza. Tutto il codice vuole accedere alla singola istanza può ancora chiamare S :: getInstance () senza ingombrare i loro costruttori richiedendo esplicitamente il istanza da passare. L'impostazione predefinita può essere ancora pigramente inizializzato nel codice di produzione, ma per il test può ancora essere deriso.
Nella risposta referenziata il primo vantaggio di DI è elencato come:
It makes the code easier to read; you can clearly understand from
the interfaces exactly what data the dependent classes depend on.
Ma perché non è una violazione dell'incapsulamento? Ho davvero bisogno di sapere dall'interfaccia pubblica tutto ciò che accede al SingleInstance / Database / etc?
Supponiamo di avere un database e 30 TableGateway responsabili delle classi per le operazioni CRUD su quelle tabelle. Nell'approccio DI TableGateway i costruttori accetterebbero il Database nel suo costruttore. Poi un la classe di business logic accetta le tabelle con cui collabora / utilizza:
class BusinessLogic {
BusinessLogic(Table1 t1, Table2 t2, Table3 t3);
void doBusiness() {
t1_.query(...);
t2_.insert(...);
t3_.update(...);
}
}
In che modo questo sfasamento di dipendenze esplicite nel costruttore consiglia?