2009-12-14 3 views
5

Chciałbym:ServiceLocator i Open/Closed Zasada

  1. Bądź powszechnie wymagane usługi widoczne dla wszystkich klas, które ich potrzebują,
  2. z minimum boilerplate i
  3. bez poświęcania testowalności !

To mały projekt i myślę, że DI może być przesadą, ale może się mylę? Tak czy inaczej, zostały koncentrując się na ServiceLocator pattern as described by Martin Fowler

w klasie klienta konstruktora, mam coś takiego:

this->db = Locator::getDb(); 
this->log = Locator::getLogger(); 

to reszta klasy metody dostępu do usługi poprzez atrybuty te państwa, na przykład :

this->fooModel = new fooModel(this->db); 
fooItem1234 = this->fooModel->findById(1234); 

jednak Chciałbym również ten poziom widoczności obiektów „model” (jak wyżej), ponieważ fooModel są one dostępne z kilku różnych miejscach i nie ma potrzeby, aby mieć więcej niż jedną instancję.

Tak więc początkowo sądziłem, że przedłużam lokalizator, aby mieć ::getFooModel(), ale teraz wydaje mi się, że naruszam zasadę otwartą/zamkniętą, ponieważ będę musiał zmodyfikować lokalizator za każdym razem, gdy wprowadzę nową klasę modelu.

Aby usatysfakcjonować OCP, mógłbym skorzystać z Lokalizatora Usług Dynamicznych (również opisanego na stronie Fowlera), ale nie jestem do końca sprzedany z tego samego powodu, co on, tzn. Nie jest wystarczająco wyraźny.

Innym rozwiązaniem byłoby po prostu uczynienie wszystkich metod moich modeli statycznymi. A więc:

fooItem1234 = FooModel::findById(1234); 

Podoba mi się to, ponieważ jest to zero. Mogę po prostu utworzyć nową klasę modelu i zacząć wywoływać ją z dowolnego miejsca za pomocą pojedynczej linii. Ale teraz model zależy od lokalizatora, aby znaleźć jego połączenie DB i nie jestem pewien, co o tym myślę. Po pierwsze, gdybym kiedykolwiek potrzebował dwóch otwartych fooModeli na oddzielnych połączeniach z bazą danych, byłby to bałagan i/lub niemożliwe. To powiedziawszy, nie muszę tego teraz robić, więc ta opcja wydaje się trochę kusząca.

Wreszcie jest DI. Ale jak powiedziałem powyżej, myślę, że może to być za dużo dla tego małego projektu.

Wniosek: Trochę utknąłem tutaj i będę wdzięczny za porady od guru z StackOverflow!

Odpowiedz

7

Dlaczego uważasz, że DI jest przesadny dla twojego projektu? Wzory DI, takie jak Konstruktor wtrysku jest o wiele prostszy i czystszy niż lokalizator usług (który uważam za wzorzec przeciwwodny).

Uważam, że Service Locator jest wzorcem zapobiegającym, ponieważ jest całkowicie nieprzejrzysty dla użytkownika interfejsu API, który musi być zainstalowany; w ten sposób można łatwo wywoływać metody na twoich obiektach w kontekście, w którym wylądowałby Service Locator, a API nie daje absolutnie żadnego pojęcia, że ​​tak właśnie jest.

Nie potrzebujesz pojemnika DI, aby użyć DI. Jeśli masz prosty projekt, możesz użyć tego, co nazywa się Poor Mana DI, gdzie ręcznie podłączasz zależności.

+0

Tak, miałem na myśli użycie pojemnika, kiedy powiedziałem, że myślę, że DI będzie przesadą, przepraszam. I dzięki za odpowiedź! Biorę to, kiedy mówisz, że Constructor Injection mówisz, że powinienem po prostu przekazać moje obiekty dbconn i logger do konstruktorów klas, które od nich zależą? Jeśli tak, to właśnie to robiłem. Następnie z jakiegoś powodu zdecydowałem, że dodanie loggera do konstruktora prototypu każdej klasy było złe. Ale teraz, kiedy zmusiłeś mnie do przemyślenia tego, wydaje się, że ma on dużo więcej sensu niż to, co próbowałem zrobić z tym ServiceLocatorem. – oops

+1

Cool. W takim przypadku zwykle tworzy się stosy zależności. Prawdopodobnie będziesz mieć wiele usług niskiego poziomu, ale często możesz zawrzeć dwa lub trzy z nich w znaczących obiektach, a następnie wstrzyknąć tylko jedną z nich zamiast trzech usług niskiego poziomu. Możesz powtórzyć to tyle razy, ile chcesz, aby liczba zależności spadła w przypadku poszczególnych klas. –

+0

Co powiesz na układanie/pakowanie rzeczy nie do końca powiązanych - jak na przykład DBconn i logger z powyższego przykładu - do jednego obiektu o nazwie "config" lub czy jest to zła forma? – oops

3

... i nie ma potrzeby, aby mieć więcej niż jedno wystąpienie.

Mieszacie jabłka i pomarańcze. Fakt, że potrzebujesz tylko jednej instancji klasy dla aplikacji, nie jest tym samym, co dobrym pomysłem jest udostępnienie tej instancji na całym świecie. Przy DI nie zmieniasz liczności - jest tylko jedna instancja. Zmieniasz zakres zmiennych, które odnoszą się do wspomnianej instancji. Jest różnica.