Chciałbym:ServiceLocator i Open/Closed Zasada
- Bądź powszechnie wymagane usługi widoczne dla wszystkich klas, które ich potrzebują,
- z minimum boilerplate i
- 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!
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
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. –
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