2012-02-03 10 views
5

Widziałem ten wiersz kodu w kilku samouczkach dotyczących używania Unity w asp.net mvc3. Miałem wrażenie, że Service Locator to anty-wzór, a nie najlepsza praktyka. Czy ten Service Locator jest czymś innym niż zdefiniowany anty-wzór, czy ta linia kodu/ta implementacja jest uważana za złą praktykę.Dlaczego Unity korzysta z Lokalizatora Usług?

ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(Container)); 
+0

Widziałem to również bardzo często, w Prism StockTrader RI, oni również używają ServiceLocator z MEF. Miałem również wrażenie, że to anty-wzór, dlatego jestem zaskoczony, widząc go w RI. Sądzę, że jest to ta sama implementacja wzorca Service Locator, co zdefiniowany wzorzec anti-pattern. – Lukazoid

+0

Dostałeś to w tył: na twoim przykładzie to nie Jedność korzysta z lokalizatora usług, ale twoja wtyczka kodu jest w jedności z asp.net mvc3 za pośrednictwem lokalizatora usług. Debaty na temat wzoru Service Locator mają charakter religijny. Zespół asp.net mvc musiał zapewnić sposób na wykorzystanie ulubionego kontenera DI i to jest sposób, w jaki go zaimplementowali. Pomyśl o alternatywach. Oto trochę więcej informacji na temat problemu: http://blog.ploeh.dk/2011/08/25/ServiceLocatorRolesVsMechanics.aspx –

+0

@ zespri - więc nie wszystkie wdrożenia Unity korzystają z Lokalizatora Usług? –

Odpowiedz

0

To jest ten sam antypatat, o którym ludzie mówią. Wszystko, co robi ta linia, to ustawienie dostawcy usługi lokalizatora na instancję UnityServiceLocator, tj. Użycie implementacji Unity w ISerivceLocator. Opcjonalnie, jeśli chcesz, możesz mieć własną implementację IServiceLocator i używać go zamiast UnityServiceLocator.

Korzystanie z lokalizatora usług jest uważane za złą praktyką z różnych powodów wymienionych here

+0

Zgadzam się, że usługa lokalizator jest złą praktyką, po prostu nie byłem pewien, czy był używany tylko z nazwy. –

+3

Jeśli używasz kontenera IOC, jak znaleźć pojemnik? –

+0

Ma swoje miejsce, zobacz inną odpowiedź, uwalnia twój kod od bezpośredniego powiązania z konkretną implementacją DI. – Alwyn

7

Jeśli stworzenie ram, które jest przeznaczone do pojemnika agnostycznego lokalizatora usług (choć powinno to być no-go w aplikacji) to dodatkowa warstwa pośrednia, która pozwala na zamianę Unity na coś innego. Ponadto użycie lokalizatora usług nie wymusza użycia DI dla aplikacji korzystających z tego środowiska.

9

Stare pytanie, ale dla dobra innych:

A ja absolutnie zgadzam się z mantrą „Usługa lokalizacji jest anty-pattern”, na pewno są wyjątki od tej reguły.

Kiedy używasz Dependency Injection (jak Unity), to tak, z pewnością nie korzystaj z ServiceLocator i używaj tylko wtrysku konstruktora dla wszystkich twoich klas usług. (Nie używaj też "nowego" do niczego innego niż obiekty wartości, takie jak DTO).

Jednak są przypadki, w których po prostu nie można użyć wstrzyknięcia konstruktora, a jedynym sposobem uzyskania dostępu do usługi jest użyj obejścia, aby uzyskać bezpośredni dostęp do kontenera Unity iw takich przypadkach ServiceLocator jest dobrym standardowym sposobem na osiągnięcie tego. Jest tak w przypadku, gdy klasa nie jest tworzona przez ciebie (lub dokładniej, nie jest tworzona przez Unity), ale na przykład przez framework .NET.

Kilka prostych przykładów gdzie ServiceLocator może być przydatny, to w celu uzyskania dostępu do usług zarejestrowanych w kontenerze Unity od:

  1. implementacji WCF IEndpointBehavior lub IClientMessageInspector
  2. implementacji WPF IValueConverter
  3. lub niekoniecznie chcesz uzyskać dostęp do "usług" z klasy, ale po prostu chcesz napisać kod, który jest testowany jednostkowo, ale z jakiegoś powodu klasa nie może być w ogóle inicjowana (lub niełatwo), ponieważ normalnie byłby zbudowany przez .NET Framework, s o wyodrębniasz swój kod niestandardowy do klasy, którą można przetestować, i rozwiązujesz go w klasie, która nie jest testowalna, za pomocą ServiceLocator.

Zauważ, że linia ta nie jest idealna:

ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(Container)); 

Obiekt ServiceLocator.Current zamierza wykonać delegat warunkiem każdym razem, gdy dostęp prąd, czyli nowy UnityServiceLocator dostanie tworzone za każdym razem, .Zamiast tego, prawdopodobnie chcesz to zrobić:

IServiceLocator locator = new UnityServiceLocator(container); 
ServiceLocator.SetLocatorProvider(() => locator);