Czy wzór „centrum powiadomień” zachęca do dobrego lub złego zaprojektowania programu?

13

Czasami spotykam te interfejsy API w stylu koncentratora komunikatów, na przykład Cocoa NSNotificationCenter: http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/Reference/Reference.html

Zwykle te interfejsy API zapewniają globalny punkt dostępu, w którym subskrybujesz lub emitujesz wiadomości / zdarzenia. Myślę, że jest to problem, ponieważ zachęca do płaskiej i nieustrukturyzowanej architektury programu, w której zależności nie są jawne w interfejsie API, ale ukryte w kodzie źródłowym. Nie musisz myśleć o własności obiektu i hierarchiach, ale możesz sprawić, że dowolny obiekt w programie spowoduje wywołanie dowolnego kodu w dowolnym miejscu. Ale może to dobra rzecz?

Czy ten wzorzec ogólnie zachęca do dobrego lub złego zaprojektowania programu i dlaczego? Czy to utrudnia lub ułatwia testowanie kodu?

Wybacz mi, jeśli to pytanie jest zbyt niejasne lub ogólne. Staram się omijać potencjalne konsekwencje częstego używania takiego interfejsu API i różne sposoby jego wykorzystania.

Edycja: Myślę, że moim największym problemem z tym wzorcem jest to, że API „kłamie” na temat zależności i sprzężeń obiektowych i można to zilustrować za pomocą tego przykładu:

myObj = new Foo();
myOtherObj = new Bar();
print myOtherObj.someValue; // prints 0
myObj.doSomething();
print myOtherObj.someValue; // prints 1, unexpectedly, because I never indicated that these objects had anything to do with each other
Magnus Wolffelt
źródło
Czy kwestionujesz ten przykład, czy ogólnie wzorzec słuchacza?
TheLQ
Wierzę, że jest to szersze niż wzorzec słuchacza. Wzorzec detektora może być zaimplementowany „czysto” z dobrze zdefiniowaną strukturą obiektu i rejestrowaniem detektorów na określonych obiektach. Moja niepewność dotyczy globalnego wzorca centrum wiadomości / zdarzeń.
Magnus Wolffelt

Odpowiedzi:

6

Nie posunąłbym się nawet do stwierdzenia, że ​​zachęca to do złego programowania. Ale można go łatwo nadużyć.

Jaki jest rzeczywisty pomysł?
Źródło powiadomienia powoduje tylko jego powiadomienie. Nie zakłada się istnienia potencjalnych obserwatorów ani nic takiego. Obserwator rejestruje powiadomienia, które ma obsługiwać. Obserwator nie przyjmuje żadnych założeń dotyczących liczby potencjalnych źródeł powiadomień, które może obsłużyć.

Jest to sposób na osiągnięcie zastrzyku zależności, bez posiadania źródeł znających obserwatorów lub obserwatorów znających źródła. Jednak aby cały system działał, należy podłączyć odpowiednich obserwatorów, aby otrzymywać odpowiednie powiadomienia, a system ten jest nawet podatny na literówki, ponieważ nie można sprawdzić czasu kompilacji.

Największe niebezpieczeństwo polega oczywiście na tym, że ktoś użyje tego, aby udostępnić masę obiektów na całym świecie dla połączeń 1-1.

back2dos
źródło
6

Przesyłanie asynchroniczne jest dobrą zasadą architektoniczną dla dużych systemów, które muszą być skalowane

Odpowiednikiem Java jest JMS i ogólnie uważa się go za dobrą rzecz .

Jest tak, ponieważ promuje oddzielenie kodu klienta od kodu, który faktycznie obsługuje wiadomość. Kod klienta musi jedynie wiedzieć, gdzie opublikować wiadomość. Kod serwisowy musi jedynie wiedzieć, gdzie odbierać wiadomości. Klient i usługa nie znają się od siebie nawzajem i dlatego mogą się zmieniać niezależnie od siebie, zgodnie z wymaganiami.

Możesz łatwo uzewnętrznić identyfikator URI centrum wiadomości, aby był konfigurowalny i nie był osadzony w kodzie źródłowym.

Gary Rowe
źródło
4

Jest to typowa implementacja wzorca Oberservera (czasem nazywana wzorcem nasłuchiwania lub czasem wzorzec subskrybenta / wydawcy). W aplikacjach, w których jest to użyteczne zachowanie, warto wdrożyć dobry wzorzec. Nie należy wdrażać żadnego wzorca, jeśli nie wnosi on żadnej wartości do rozwiązania.

Z twojego pytania brzmi to tak, jakbyś martwił się, że wszystko wie o NotificationCenter i że rzeczy globalne są ZŁE. Czasami tak, globalne rzeczy są złe. Ale spójrzmy na alternatywę. Załóżmy, że masz 2 komponenty, w tym przykładzie tak naprawdę nie ma znaczenia, co robią lub czym są. Składnik 1 zawiera pewne dane, które zostały zmodyfikowane lub w jakiś sposób zmienione. Komponent2 chciałby wiedzieć o wszelkich zmianach danych typu zarządzanego przez Compoent1. Czy Component2 powinien wiedzieć o istnieniu Component1? Czy może lepiej byłoby zasubskrybować / nasłuchiwać Component2 wiadomości, która mówi, że jakiś komponent w aplikacji zmienił niektóre dane, którymi jest zainteresowany? Teraz weź ten przykład i pomnóż go przez dziesiątki lub więcej składników, a zobaczysz, gdzie leży wartość wzoru.

Czy to idealne rozwiązanie na każdą sytuację, nie. Czy abstrakcyjnie komunikuje się między komponentami i zapewnia bardziej luźne połączenie, tak.

Walter
źródło
1
Czytając wikipedię, definicja wzorca obserwatora nie obejmuje globalnie dostępnego centrum wydarzeń. Gdyby centrum zdarzeń zostało przekazane do konstruktora / metody wszystkich przedmiotowych obiektów, uznałbym to za dobry wzorzec. Rzeczywiście to globalny punkt dostępu i jego stan sprawiają, że jestem niepewny.
Magnus Wolffelt
0

Jest dobry dla systemów sterowanych zdarzeniami i jest ładniejszy niż alternatywa obserwowania siebie przez grupę obserwatorów, ponieważ mniej prawdopodobne jest, że skończysz z nieumyślnymi nieskończonymi pętlami obserwatorów odpalającymi zdarzenia. Był to prawdziwy problem w dawnych czasach VB, kiedy miałeś kontrolki ActiveX sterowane zdarzeniami, które można było połączyć ze sobą za pomocą procedur obsługi zdarzeń.

TMN
źródło