Service Locator è solo il minore di due mali per così dire. Il "minore" che si riduce a queste quattro differenze ( almeno non riesco a pensare ad altre in questo momento ):
Principio di responsabilità unica
Il contenitore di servizi non viola il principio di responsabilità singola come fa Singleton. I singleton combinano la creazione di oggetti e la logica aziendale, mentre il contenitore dei servizi è strettamente responsabile della gestione dei cicli di vita degli oggetti della tua applicazione. A questo proposito, Service Container è migliore.
Accoppiamento
I singleton sono solitamente codificati nell'applicazione a causa delle chiamate al metodo statico, il che porta a dipendenze strettamente accoppiate e difficili da simulare nel codice. La SL d'altra parte è solo una classe e può essere iniettata. Quindi, mentre tutta la tua classe dipenderà da questo, almeno è una dipendenza vagamente accoppiata. Quindi, a meno che tu non abbia implementato ServiceLocator come Singleton stesso, è leggermente migliore e anche più facile da testare.
Tuttavia, tutte le classi che utilizzano ServiceLocator ora dipenderanno da ServiceLocator, che è anche una forma di accoppiamento. Questo può essere mitigato utilizzando un'interfaccia per ServiceLocator in modo da non essere vincolato a un'implementazione concreta di ServiceLocator, ma le tue classi dipenderanno dall'esistenza di una sorta di Locator, mentre il mancato utilizzo di un ServiceLocator aumenta notevolmente il riutilizzo.
Dipendenze nascoste
Tuttavia, il problema di nascondere le dipendenze esiste molto. Quando inietti il localizzatore nelle tue classi che consumano, non conoscerai alcuna dipendenza. Ma a differenza di Singleton, SL di solito istanzia tutte le dipendenze necessarie dietro le quinte. Quindi, quando prendi un servizio, non finisci come Misko Hevery nell'esempio della carta di credito , ad esempio non devi istanziare a mano tutte le dipendenze delle dipendenze.
Recuperare le dipendenze dall'interno dell'istanza viola anche la Legge di Demetra , che afferma che non dovresti scavare nei collaboratori. Un'istanza dovrebbe parlare solo con i suoi collaboratori immediati. Questo è un problema con Singleton e ServiceLocator.
Stato globale
Anche il problema dello stato globale è in qualche modo mitigato perché quando si istanzia un nuovo Service Locator tra i test vengono eliminate anche tutte le istanze create in precedenza (a meno che non si sia commesso l'errore e le si sia salvate in attributi statici nella SL). Ciò non vale per nessuno stato globale nelle classi gestite da SL, ovviamente.
Vedi anche Fowler su Service Locator vs Dependency Injection per una discussione molto più approfondita.
Una nota sul tuo aggiornamento e l'articolo collegato di Sebastian Bergmann sul test del codice che utilizza Singletons : Sebastian non suggerisce in alcun modo che la soluzione alternativa proposta renda l'utilizzo di Singleons meno problematico. È solo un modo per rendere più testabile un codice che altrimenti sarebbe impossibile testare. Ma è ancora un codice problematico. Infatti, osserva esplicitamente: "Solo perché puoi, non significa che dovresti".