Jakie są zalety wzorca delegowania w porównaniu do wzorca obserwatora?

9

We wzorze delegowanym tylko jeden obiekt może bezpośrednio nasłuchiwać zdarzeń innego obiektu. We wzorcu obserwatora dowolna liczba obiektów może nasłuchiwać zdarzenia określonego obiektu. Kiedy projektując klasę, która musi powiadamiać inne obiekty o zdarzeniach, dlaczego miałbyś kiedykolwiek używać wzorca delegowanego zamiast wzorca obserwatora? Widzę wzorzec obserwatora jako bardziej elastyczny. Możesz mieć tylko jednego obserwatora, ale przyszły projekt może wymagać wielu obserwatorów.

JoJo
źródło
4
Co rozumiesz przez „wzór delegowania”? Jeśli mówisz o czymś takim jak delegaci .net, możesz mieć tyle subskrybentów, ile chcesz.
CodesInChaos,
Powiązane, choć bardziej skoncentrowane na Cocoa: NSNotificationCenter vs delegacja (przy użyciu protokołów)?
mouviciel

Odpowiedzi:

7

Sam w sobie nie ma wzorca delegowania. Zakładam, że masz na myśli wzór delegacji .

Jak rozumiem, są one kompletnie odwrotne i używane do różnych celów.

Zasadniczo we Wzorze obserwatora dowolna liczba obiektów obserwatora będzie nasłuchiwała zdarzenia na drugim obiekcie i działała na nim. Drugi obiekt nie ma wiedzy o swoich słuchaczach. Po prostu do nich wzywa.

Obiekt delegowany jest przekazywany do drugiego obiektu, który wywołuje metody bezpośrednio w delegacie. I na tym polega przewaga, której szukasz. Zamiast wysyłać jedną wiadomość do wielu słuchaczy, ma ona pełną kontrolę nad jednym obiektem (w danym momencie). Zobacz także Odwrócenie kontroli .

pdr
źródło
6

Patrzysz na rzeczy niepoprawnie. Obserwator widzi, że ma miejsce określone zdarzenie. Nie ma na to wpływu ani nie jest jego właścicielem. Delegat obsługuje określone zdarzenie i jest właścicielem procedury obsługi, nawet jeśli delegat jest właścicielem interfejsu do zdarzenia.

Telastyn
źródło
1
Delegat naprawdę jest niczym więcej niż obserwatorem wydarzenia. Delegat nie musi niczego „obsługiwać”. Nie może nic zrobić bezpiecznie i nie wpłynie (a przynajmniej nie powinno) wpłynąć na instancję, która wywołała zdarzenie.
Marjan Venema,
5
@MarjanVenema - jeżeli przedmiot A nie jest delegowanie odpowiedzialności za zdarzenia do obiektu B, nie jesteś przy użyciu wzorca delegacji: używasz wzorca obserwatora z tylko jednego obserwatora.
Telastyn
Tak, właśnie o tym myślałem. Rozumiałem, że delegowane są typy sygnatur zdarzeń, które mają być używane przez subskrybenta zdarzenia „OnWhthing”. Najwyraźniej delegaci w języku C # nie są pojedynczymi subskrybentami, jak na przykład w Delphi.
Marjan Venema
@Marjan Venema „Delegat naprawdę jest niczym więcej niż obserwatorem wydarzenia”. - zależy od tego, o jakim języku mówisz. W celu C niektórzy delegaci są odpowiedzialni za dostarczanie danych - np. Delegaci danych - a obiekt brakujący delegata danych nie ma danych do przedstawienia. W takich przypadkach dochodzi do delegacji, odrębnej od samego obserwowania czegoś.
Occulus,
1
@occulus: dzięki za wyjaśnienie. Szkoda, że ​​języki nie mogą się zgodzić na terminologię ... Mówienie o programowaniu w sposób agnostyczny z językiem staje się nieco trudne, gdy ludzie rozumieją różne rzeczy dla tych samych słów.
Marjan Venema,
4

To kwestia kilku kompromisów.

Kompromisy:

  • elastyczność (pod względem posiadania n> 1 delegatów / obserwatorów)
  • koszt wysłania wiadomości
  • odporność (zdolność do utrzymania niedostępności delegata / obserwatorów)
  • łatwość użycia

Deleguj wzór:

  • niezbyt elastyczny - dodanie więcej niż 1 delegata nie jest możliwe (implikuje pewną formę „wielu delegatów”, tj. wzorca obserwatora)
  • wysyłanie wiadomości jest tanie, O (1) - taki sam koszt jak wywołanie jakiejkolwiek innej funkcji lub metody (nie jest wymagane wyszukiwanie, kolejka komunikatów ani inna infrastruktura)
  • zwykle nie jest odporny - oczekuje się, że delegaci będą obecni i wykonują swoją część pracy, tj. nadawca zwykle ponosi porażkę, jeśli nie jest znany delegat
  • łatwe do uchwycenia, łatwe do wdrożenia

Wzór obserwatora:

  • bardzo elastyczny - z założenia oczekuje się dodania n> 1 obserwatora
  • wysłanie wiadomości wiąże się z kosztem wynikającym z liczby obserwatorów, O (n), tzn. n obserwatorów zajmuje n czasu i wiadomości (przynajmniej w naiwnej implementacji)
  • zwykle odporny - zwykle nie oczekuje się, że obserwatorzy wykonają jakąkolwiek pracę ze strony nadawcy. Dzieje się tak nawet wtedy, gdy nie ma obserwatora, nadawca pozostaje nienaruszony
  • może stać się trudniejszy do uchwycenia, w szczególności oczekuje się, że obserwatorzy zareagują na wiadomości (czy kolejność ma znaczenie ?, który obserwator odpowiada w jaki sposób?)
miraculixx
źródło
1

Wzorzec delegowania, jak rozumiem, jest znany jako mechanizm obsługi zdarzeń w innych językach, na przykład Delphi. Jako taka jest po prostu implementacją wzorca obserwatora z dużym ograniczeniem: tylko jeden słuchacz na raz.

Wada programów obsługi zdarzeń lub delegatów jest oczywista: tylko jeden obserwator.

Zaleta nie jest tak oczywista: wydajność. Za pomocą wzorca obserwatora możesz dodać wielu obserwatorów. Gdy wystąpi zdarzenie, o którym należy powiadomić obserwatora, należy wymienić go i wysłać do każdego z nich powiadomienie. Może to szybko zniszczyć każdą zaobserwowaną instancję, szczególnie gdy liczba zdarzeń wymagających powiadomienia jest również znacząca.

Marjan Venema
źródło
Co? Delegat w języku C # jest tylko podpisem metody jako typu zmiennej (równoważnej na przykład int (*my_int_f)(int)w języku C). Zawsze myślałem, że ułatwią to zrozumienie, sprawiając, że będzie działać bardziej jak struct / enum. Wydarzenie to haczyk dla elastycznej tablicy słuchaczy, wykorzystującej pojedynczy podpis delegata. Mógłbyś to zrobić bez zdarzenia (dlatego zakładam, że OP oznaczało wzorzec delegacji, który jest bardzo inny), ale język ułatwia ci to.
pdr
hmm Jeszcze nie tak dobrze zorientowany w C #. Zrozumiałem, że delegaci są odpowiednikami typów sygnatur zdarzeń używanych przez zdarzenia „OnWhthing” na przykład w Delphi. Czyli zdarzenia C # mogą być subskrybowane przez wielu słuchaczy?
Marjan Venema
Ogólna akcja <T> jest delegatem. Nie ma to nic wspólnego ze zdarzeniami, jest zmienną, która jest przekazywana. I tak, wielu słuchaczy może słuchać jednego zdarzenia.
pdr
ok dzięki, mam nadzieję, że uda mi się to utrzymać prosto: :-) Wziąłem odniesienie do C # i skupiłem się bardziej na mechanizmie zdarzeń.
Marjan Venema
1

To jest stary post, ale i tak będę dzwonił, ponieważ inne odpowiedzi nie dotyczą tego, co dzieje się przy użyciu któregokolwiek z wzorów, wydaje się, że bardziej dotyczą teorii niż praktyki.

Jak działają delegacje i obserwatorzy

Dzięki Delegacji delegujący wybiera dokładnie, kto ma zareagować na dane zdarzenie w momencie utworzenia źródła potencjalnego zdarzenia. Możesz uważać tego słuchacza za jednego obserwatora . W przypadku wzorca Obserwator obserwator wybiera, kogo obserwuje, kiedy tylko ma na to ochotę; więc zależności są odwrócone, jeśli chodzi o obserwatora a delegację. Wzorem obserwatora myśl o gazecie i subskrybentach jak o obserwatorze. Obserwatorzy kontrolują, kiedy relacja zostanie utworzona. Z delegacją pomyśl o pracowniku i pracodawcy. Pracodawca kontroluje, kiedy tworzony jest związek i kto dokładnie odpowiada za określone wydarzenia. Pracownicy nie mogą wybrać zadań, nad którymi pracują ... ogólnie.

Niektórzy twierdzą, że delegacja może mieć jednego obserwatora, ale myślę, że prawdziwą różnicą między nimi jest sposób przypisywania obsługi zdarzeń. Nigdy nie zobaczysz delegata zarejestrowanego na wydarzenie. Nigdy się nie dowie, że nawet obsługuje zdarzenie, dopóki się ono nie wydarzy, a delegator wywoła publiczną metodę.

Przewaga delegacji

Ten wzór jest bardzo sztywny, a przy większości regresywnych projektów jest prostszy i ogólnie bardziej wytrzymały. Zmusza cię do zadeklarowania procedury obsługi zdarzeń z góry w momencie inicjowania źródła potencjalnego zdarzenia. Jeśli potrzebujesz kogoś do kierowania ruchem, przed otwarciem ulicy wyznaczysz dyrektora ruchu. W przypadku obserwatora pozwoliłbyś policjantowi ruchowemu wybrać, kiedy kierować ruchem w dowolnym momencie.

Wada delegacji

Wadą tego projektu jest to, że nie jest elastyczny. Jeśli wdrażasz jakiś kod do subskrybowania gazety, gazeta / delegator będzie musiał dokładnie określić, kto może czytać wiadomości w momencie ich tworzenia. Dzięki wzorowi obserwatorów można je później zarejestrować w dowolnym momencie, a gazeta będzie musiała jedynie wiedzieć, że zapisała się nowa osoba.

Kiedy wybrać delegację?

Jeśli na pewno potrzebujesz jednego konkretnego obserwatora (ów) i nie ma powodu, aby zmieniać osobę obserwującą, korzystny będzie sztywny wzór schematu przekazania uprawnień.

Na przykład potrzebujesz klasy / obiektu do obsługi tworzenia wyskakującego okienka dla określonego błędu. Nie ma wielu powodów, dla których w czasie wykonywania trzeba by było zmienić osobę zajmującą się konkretnym błędem, więc delegowanie błędu „Brak pamięci” do jednej jednostki byłoby sensowne. Utworzenie tablicy potencjalnych procedur obsługi, a następnie zarejestrowanie tych procedur pod kątem błędu „Brak pamięci” nie miałoby większego sensu; byłby to przykład użycia wzorca obserwatora w tej sytuacji. W czasie wykonywania możesz chcieć zmienić, które metody będą wywoływane lub jakie „delegowane” będą wywoływane dla zdarzeń zmiennych, ale zamiana programu obsługi zdarzeń dla określonego zdarzenia w czasie wykonywania nie jest normalna.

Nie jest niemożliwe zamiana delegatów, tak jak w przypadku obserwatora, jest to po prostu skomplikowane. W prawdziwym świecie być może chcesz zamienić policjantów z ruchu, aby nowy delegat obsługiwał ruch. Można argumentować, że lepszy projekt sprawiłby, że oryginalny delegat oddelegowałby komisariat policji, a nie jednego policjanta, ale dygresję ...

Usman Mutawakil
źródło