Service Locator est juste le moindre de deux maux pour ainsi dire. Le «moindre» se résumant à ces quatre différences ( du moins, je ne peux penser à aucune autre pour le moment ):
Principe de responsabilité unique
Le conteneur de services ne viole pas le principe de responsabilité unique comme le fait Singleton. Les singletons mélangent la création d'objets et la logique métier, tandis que le conteneur de services est strictement responsable de la gestion des cycles de vie des objets de votre application. À cet égard, Service Container est meilleur.
Couplage
Les singletons sont généralement codés en dur dans votre application en raison des appels de méthode statiques, ce qui conduit à des dépendances étroitement couplées et difficiles à simuler dans votre code. Le SL en revanche n'est qu'une classe et il peut être injecté. Ainsi, bien que tous vos classifiés en dépendent, au moins c'est une dépendance faiblement couplée. Donc, à moins que vous n'implémentiez le ServiceLocator en tant que 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 du ServiceLocator, qui est également une forme de couplage. Cela peut être atténué en utilisant une interface pour ServiceLocator afin que vous ne soyez pas lié à une implémentation concrète de ServiceLocator, mais vos classes dépendront de l'existence d'une sorte de localisateur alors que le fait de ne pas utiliser de ServiceLocator augmente considérablement la réutilisation.
Dépendances cachées
Le problème du masquage des dépendances existe cependant. Lorsque vous injectez simplement le localisateur dans vos classes consommatrices, vous ne connaîtrez aucune dépendance. Mais contrairement au Singleton, le SL instanciera 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 comme Misko Hevery dans l'exemple de CreditCard , par exemple , vous n'avez pas à instancier toutes les dépendances des dépendances à la main.
Récupérer les dépendances à l'intérieur de l'instance enfreint également la loi de Demeter , qui stipule que vous ne devez pas fouiller dans les collaborateurs. Une instance ne doit parler qu'à ses collaborateurs immédiats. Il s'agit d'un problème avec Singleton et ServiceLocator.
État mondial
Le problème de l'état global est également quelque peu atténué car lorsque vous instanciez un nouveau localisateur de service entre les tests, toutes les instances créées précédemment sont également supprimées (sauf si vous avez fait l'erreur et les avez enregistrées dans des attributs statiques dans le SL). Cela n'est vrai pour aucun état global dans les classes gérées par le SL, bien sûr.
Voir également Fowler sur Service Locator vs Dependency Injection pour une discussion beaucoup plus approfondie.
Une note sur votre mise à jour et l'article lié de Sebastian Bergmann sur le test de code qui utilise des Singletons : Sebastian ne suggère en aucun cas que la solution de contournement proposée rend l'utilisation de Singleons moins problématique. C'est juste une façon de rendre le code qu'il serait autrement impossible de tester plus testable. Mais c'est toujours du code problématique. En fait, il note explicitement: "Juste parce que vous pouvez, ne signifie pas que vous devriez".