Service Locator n'est que le moindre des deux maux, pour ainsi dire. Le "moindre" se résume à ces quatre différences ( en tout cas, je n'en vois pas d'autres pour le moment. ):
Principe de responsabilité unique
Le conteneur de service ne viole pas le principe de responsabilité unique comme le fait le singleton. Les singletons mélangent la création d'objets et la logique métier, tandis que le Service Container est strictement responsable de la gestion des cycles de vie des objets de votre application. À cet égard, le Service Container est meilleur.
Accouplement
Les singletons sont généralement codés en dur dans votre application en raison des appels de méthodes statiques, ce qui conduit à couplage étroit et dépendances difficiles à simuler dans votre code. Le SL, quant à lui, n'est qu'une classe et il peut être injecté. Ainsi, même si toutes vos classes en dépendent, il s'agit au moins d'une dépendance faiblement couplée. Donc, à moins que vous n'implémentiez le ServiceLocator comme un Singleton lui-même, c'est un peu mieux et aussi plus facile à tester.
Cependant, toutes les classes utilisant le ServiceLocator dépendront désormais de ce dernier, ce qui constitue également une forme de couplage. Cela peut être atténué en utilisant une interface pour le ServiceLocator afin de ne pas être lié à une implémentation concrète du ServiceLocator mais vos classes dépendront de l'existence d'une sorte de Locator alors que ne pas utiliser de ServiceLocator du tout augmente considérablement la réutilisation.
Dépendances cachées
Le problème de la dissimulation des dépendances existe cependant bel et bien. Lorsque vous injectez simplement le localisateur à vos classes consommatrices, vous ne connaissez pas les dépendances. Mais contrairement au Singleton, le SL instancie généralement toutes les dépendances nécessaires dans les coulisses. Ainsi, lorsque vous récupérez un service, vous ne vous retrouvez pas dans la situation suivante Misko Hevery dans l'exemple de CreditCard Par exemple, vous n'avez pas à instancier toutes les dépendances à la main.
Récupérer les dépendances à partir de l'intérieur de l'instance est également une violation Loi de Déméter qui stipule que vous ne devez pas fouiller dans les collaborateurs. Une instance ne doit parler qu'à ses collaborateurs immédiats. C'est un problème à la fois avec Singleton et ServiceLocator.
État global
Le problème de l'état global est également quelque peu atténué car lorsque vous instanciez un nouveau Service Locator entre les tests, toutes les instances précédemment créées sont également supprimées (à moins que vous n'ayez commis l'erreur de les sauvegarder dans des attributs statiques dans la SL). Cela n'est pas vrai pour tout état global dans les classes gérées par le SL, bien sûr.
Voir également Fowler sur Localisation de services et injection de dépendances pour une discussion beaucoup plus approfondie.
Une note sur votre mise à jour et l'article lié par Sebastian Bergmann sur le test du code qui utilise des singletons : Sebastian ne suggère en aucun cas que la solution de contournement proposée rend l'utilisation des Singleons moins problématique. C'est juste une façon de rendre plus testable un code qui serait autrement impossible à tester. Mais c'est toujours un code problématique. En fait, il note explicitement : "Juste parce que vous pouvez, ne signifie pas que vous devriez".