Przejdź do zawartości

Obserwator (wzorzec projektowy)

Z Wikipedii, wolnej encyklopedii

Obserwator (ang. observer) – wzorzec projektowy należący do grupy wzorców czynnościowych. Używany jest do powiadamiania zainteresowane obiekty o zmianie stanu pewnego innego obiektu.

Problem

[edytuj | edytuj kod]

W programowaniu obiektowym obiekty posiadają pewien stan, tj. zbiór aktualnych wartości pól obiektu, który w wyniku wykonywania na nich operacji może ulegać zmianie. Od bieżącego stanu mogą być zależne inne obiekty, dlatego musi istnieć możliwość ich powiadomienia o jego zmianie tak, aby mogły one się do niej dostosować. Możemy także żądać, aby inne obiekty były powiadamiane o tym, że inny obiekt próbuje wykonać konkretną czynność, np. ponownie nawiązywać utracone połączenie z bazą danych. Pragniemy zaimplementować ogólny mechanizm, który umożliwi nam osiągnięcie tych celów.

Budowa

[edytuj | edytuj kod]
Diagram klas wzorca Obserwator

We wzorcu obserwator wyróżniamy dwa podstawowe typy obiektów:

  • obserwowany (ang. observable, subject) - obiekt, o którym chcemy uzyskiwać informacje,
  • obserwator (ang. observer, listener) - obiekt oczekujący na powiadomienie o zmianie stanu obiektu obserwowanego.

Kiedy stan obiektu obserwowanego się zmienia, wywołuje on metodę powiadomObserwatorow(), która wysyła powiadomienia do wszystkich zarejestrowanych obserwatorów:

public void powiadomObserwatorow() {
   dla każdego obserwatora obserwator z listy obserwatorzy:
      wywołaj obserwator.aktualizacja(this);
}

Podczas powiadamiania obserwatorzy otrzymują także referencję do obiektu obserwowanego. Jeden obserwator może obserwować kilka innych obiektów, a jeden obiekt obserwowany może być obserwowany przez kilku obserwatorów. Ponieważ oba te typy obiektów zdefiniowane są jako interfejsy do samodzielnej implementacji, obserwatorzy i obserwowani nie muszą się nawzajem znać, a ponadto obiekt obserwowany sam może obserwować inny obiekt.

Konsekwencje użycia

[edytuj | edytuj kod]

Zalety:

  • luźna zależność między obiektem obserwującym i obserwowanym. Ponieważ nie wiedzą one wiele o sobie nawzajem, mogą być niezależnie rozszerzane i rozbudowywane bez wpływu na drugą stronę,
  • relacja między obiektem obserwowanym a obserwatorem tworzona jest podczas wykonywania programu i może być dynamicznie zmieniana,
  • domyślnie powiadomienie otrzymują wszystkie obiekty. Obiekt obserwowany jest zwolniony z zarządzania subskrypcją — o tym czy obsłużyć powiadomienie, decyduje sam obserwator.

Wady:

  • obserwatorzy nie znają innych obserwatorów, co w pewnych sytuacjach może wywołać trudne do znalezienia skutki uboczne.

Implementacja

[edytuj | edytuj kod]

Obserwatorzy często potrzebują informacji o tym, co zostało zmienione w obserwowanym obiekcie. Wiąże się to z przekazaniem metodzie aktualizacja() dodatkowych argumentów. Istnieją dwie podstawowe strategie wyciągania informacji o zmianach:

  1. strategia wyciągania (ang. pull model) - obiekt obserwowany przekazuje w argumencie referencję do siebie samego, pozwalając obserwatorom na samodzielne wyciągnięcie niezbędnych informacji.
  2. strategia wpychania (ang. push model) - obiekt obserwowany przygotowuje listę zmian w określonym formacie (najczęściej jako dodatkowy obiekt z określonymi właściwościami) i przekazuje ją jako parametr wywołania obserwatorom.

Pierwsza strategia wymaga, aby obserwatorzy znali interfejsy obiektów obserwowanych, co zwiększa stopień zależności między nimi i utrudnia ich wielokrotne wykorzystanie. Z kolei w drugim przypadku wymagane jest opracowanie wystarczająco ogólnego formatu opisu zmian, aby był on niezależny od konkretnej sytuacji. Przetwarzanie takich informacji może być bardziej czasochłonne, a obserwatorzy muszą zrealizować swoje zadania bazując jedynie na otrzymanych informacjach.

Zastosowanie

[edytuj | edytuj kod]

Obserwator jest stosowany w aplikacjach z graficznym interfejsem użytkownika. Rozpatrzmy mechanizm kopiowania pliku oraz okienko graficzne obrazujące postęp prac. Mechanizm kopiujący jest niezależny od okienka i nie musi wiedzieć czy i w jaki sposób postępy są wyświetlane. Z drugiej strony, do poprawnego wyświetlania okienko potrzebuje informacji z mechanizmu kopiowania:

  • ile bajtów danych już skopiowano,
  • kiedy została skopiowana kolejna porcja danych.

Możemy zaimplementować w mechanizmie kopiowania interfejs Obserwowany, zaś w okienku - Obserwator i skomunikować je ze sobą. Mechanizm kopiowania będzie wywoływać metodę powiadomObserwatorow() po skopiowaniu bloku danych określonej wielkości, co spowoduje wysłanie powiadomienia do okienka i odświeżenie paska postępu.

Modyfikacje

[edytuj | edytuj kod]

Typowa implementacja wzorca Obserwator nie jest odpowiednia do obsługi złożonych aktualizacji. Przykładowo, jeśli obiekt obserwowany musi w ramach aktualizacji zmodyfikować kilka innych obiektów, które mogą być także obserwowane, chcielibyśmy wysłać tylko jedno zbiorcze powiadomienie o wykonaniu całej operacji, zamiast zbioru małych powiadomień od każdego obserwowanego z osobna. Można tu wykorzystać wzorzec Mediator poprzez zaimplementowanie dodatkowej klasy, MenedzerZmian, który będzie implementować konkretną strategię powiadamiania oraz separować obserwatorów i obserwowanych.

Zobacz też

[edytuj | edytuj kod]

Bibliografia

[edytuj | edytuj kod]

Linki zewnętrzne

[edytuj | edytuj kod]
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy