Service Locator to po prostu mniejsze zło, że tak powiem. „Mniejszy” sprowadzający się do tych czterech różnic ( przynajmniej nie mogę teraz wymyślić żadnych innych ):
Zasada pojedynczej odpowiedzialności
Service Container nie narusza zasady pojedynczej odpowiedzialności, tak jak robi to Singleton. Pojedyncze elementy łączą tworzenie obiektów i logikę biznesową, podczas gdy kontener usług jest ściśle odpowiedzialny za zarządzanie cyklami życia obiektów aplikacji. Pod tym względem Service Container jest lepszy.
Sprzęganie
Singletony są zwykle zakodowane na stałe w aplikacji ze względu na statyczne wywołania metod, co prowadzi do ścisłych powiązań i trudnych do makietowania zależności w kodzie. Z drugiej strony SL to tylko jedna klasa i można ją wstrzykiwać. Więc chociaż wszystkie twoje klasyfikacje będą od tego zależeć, przynajmniej jest to zależność luźno związana. Więc jeśli nie zaimplementowałeś ServiceLocator jako samego Singletona, jest to nieco lepsze i łatwiejsze do przetestowania.
Jednak wszystkie klasy używające ServiceLocator będą teraz zależały od ServiceLocator, który jest również formą sprzężenia. Można to złagodzić, używając interfejsu dla ServiceLocator, więc nie jesteś związany z konkretną implementacją ServiceLocator, ale twoje klasy będą zależeć od istnienia jakiegoś rodzaju Locatora, podczas gdy brak ServiceLocator w ogóle zwiększa ponowne użycie.
Ukryte zależności
Problem ukrywania zależności istnieje jednak bardzo mocno. Kiedy po prostu wstrzykniesz lokalizator do klas konsumujących, nie będziesz znać żadnych zależności. Ale w przeciwieństwie do Singletona, SL zwykle tworzy instancję wszystkich zależności potrzebnych za kulisami. Więc kiedy pobierasz usługę, nie kończysz jak Misko Hevery w przykładzie z kartą kredytową , np. Nie musisz ręcznie tworzyć instancji wszystkich zależności zależności.
Pobieranie zależności z wnętrza instancji również narusza prawo Demeter , które stanowi, że nie należy kopać w współpracowników. Instancja powinna rozmawiać tylko ze swoimi bezpośrednimi współpracownikami. Jest to problem związany z usługami Singleton i ServiceLocator.
Stan globalny
Problem ze stanem globalnym jest również nieco złagodzony, ponieważ podczas tworzenia instancji nowego lokalizatora usług między testami wszystkie wcześniej utworzone instancje są również usuwane (chyba że popełniłeś błąd i zapisałeś je w statycznych atrybutach w SL). Oczywiście nie dotyczy to żadnego stanu globalnego w klasach zarządzanych przez SL.
Zobacz także Fowler on Service Locator vs Dependency Injection, aby uzyskać znacznie bardziej dogłębną dyskusję.
Notatka na temat Twojej aktualizacji i link do artykułu Sebastiana Bergmanna na temat testowania kodu używającego Singletonów : Sebastian w żaden sposób nie sugeruje, że proponowane obejście sprawia, że używanie Singleonów jest mniejszym problemem. To tylko jeden ze sposobów na stworzenie bardziej testowalnego kodu, którego w innym przypadku nie byłoby możliwe do przetestowania. Ale nadal jest to problematyczny kod. W rzeczywistości wyraźnie zauważa: „Tylko dlatego, że możesz, nie oznacza, że powinieneś”.