Różnice między wybraną wersją a wersją aktualną.
Both sides previous revision Previous revision Next revision | Previous revision | ||
obserwator [2008/04/14 13:28] wojtek-j |
obserwator [2008/04/14 14:05] (aktualna) wojtek-j |
||
---|---|---|---|
Linia 1: | Linia 1: | ||
======Wzorzec Projektowy Obserwator====== | ======Wzorzec Projektowy Obserwator====== | ||
- | Wzorzec Obserwatora (ang. The Observer Pattern) jest wzorcem projektowym służącym do obserwowania stanu obiektu. Wzorzec ten jest pomyślany do rozwiązania sytuacji w której stan większej liczby obiektów (obserwatorów) zależy od stanu innego obiektu (obserwowanego) - pomaga zachować spójność między nimi. | + | Wzorzec Obserwatora (ang. The Observer Pattern) jest wzorcem projektowym służącym do obserwowania stanu obiektu. Wzorzec ten jest pomyślany do rozwiązania sytuacji w której stan większej liczby obiektów (obserwatorów) zależy od stanu innego obiektu (obserwowanego) - pomaga zachować spójność między nimi. W ogólnym przypadku działanie jego polega na rejestrowaniu przez obiekt obserwowany obiektów go obserwujących (Obserwatorów), a następnie po zmianie swojego stanu powiadomieniu wszystkich Obserwatorów o tym fakcie tak, aby każdy z nich mógł odpowiednio zaktualizować swój stan. Wzorzec jest szczególnie przydatny w przypadkach gdy rodzaj i ilość obserwatorów nie jest znana lub zmienna. |
=====Diagram UML===== | =====Diagram UML===== | ||
- | {{ observer:uml_1.jpg |}} | + | {{ observer:uml1.jpg |}} |
+ | =====Opis elementów wzorca===== | ||
+ | W skład wzorca wchodzą cztery elementy: | ||
+ | - **[[obserwator#Abstrakcyjny Obserwowany|Abstrakcyjny Obserwowany]]**: Klasa abstrakcyjna dostarczająca interfejs dla dodawania i usuwania obserwatorów, oraz powiadamiania o zmianie stanu wszystkich obserwatorów z listy. Zawiera: | ||
+ | * //dodaj//- dodaje obserwatora | ||
+ | * //usun//- usuwa obserwatora | ||
+ | * //powiadom//- powiadamia o zmianie wszystkich obserwatorow z listy poprzez wołanie metody odswież dla każdego z nich | ||
+ | - **[[obserwator#Obserwowany Konkretny|Obserwowany Konkretny]]**: Klasa zwraca swój wewnętrzny stan, który jest obiektem zainteresowania obserwatorów. Powiadamia także swoich obserwatorów na wypadek zmiany swojego stanu. Zawiera: | ||
+ | * //podaj_stan// - zwraca aktualny stan obiektu | ||
+ | - **[[obserwator#Abstrakcyjny Obserwator|Abstrakcyjny Obserwator]]**: Klasa abstrakcyjna dostarczająca interfejs dla powiadamiania dla wszystkich obserwatorów. Zawiera: | ||
+ | * //odswiez// - abstrakcyjna metoda która ma być nadpisana przez konkretnego obserwatora | ||
+ | - **[[obserwator#Obserwator konkretny|Obserwator konkretny]]**: Klasa pozostaję w związku z obiektem obserwowanym (ObserwowanyKonkretny) aby otrzymać/pobrać jego stan w wypadku powiadomienia o zmienie. Zawiera: | ||
+ | * //odswiez// - podczas wołania tej metody (która nadpisuje metode abstrakcyjną w klasie bazowej), konkretny obserwator woła podaj_stan dla obiektu obserwowanego aby zaktualizować informację o nim | ||
=====Kod w C++===== | =====Kod w C++===== | ||
+ | ====Abstrakcyjny Obserwowany==== | ||
<code cpp> | <code cpp> | ||
- | //Abstrakcyjny Obserwowany | ||
class Obserwowany { | class Obserwowany { | ||
public: | public: | ||
+ | /** | ||
+ | * dodaje obserwatora o do listy obserwatorow | ||
+ | */ | ||
void dodaj(Obserwator* o) { | void dodaj(Obserwator* o) { | ||
- | /* dodaj obserwatora o do listy obserwatorow */ | + | //dodaj obserwatora o do listy obserwatorow |
} | } | ||
+ | /** | ||
+ | * powiadamia kazdego obserwatora o zmianie stanu | ||
+ | */ | ||
void powiadom(){ | void powiadom(){ | ||
- | /* dla każdego o w obserwatorzy wywołaj o->odswiez() */ | + | //dla każdego o w obserwatorzy wywołaj o->odswiez() |
} | } | ||
- | virtual ~Obserwowany() = 0; | + | /** |
+ | * abstrakcyjny destruktor | ||
+ | */ | ||
+ | virtual ~Obserwowany() { | ||
+ | ; | ||
+ | }; | ||
private: | private: | ||
- | std::vector<Obserwator*> obserwatorzy; | + | /** |
+ | * lista obserwatorow | ||
+ | */ | ||
+ | std::vector<Obserwator*> obserwatorzy_; | ||
}; | }; | ||
- | Subject::~Subject(){} | + | </code> |
- | //Obserwowany konkretny | + | ====Obserwowany konkretny==== |
+ | <code cpp> | ||
class ObserwowanyKonkretny : public Obserwowany { | class ObserwowanyKonkretny : public Obserwowany { | ||
public: | public: | ||
- | void podaj_stan(StanObserwowanego* stan) { | + | /** |
- | /* podaj stan, np. poprzez odpowiednia struktore StanObserwowanego */ | + | * podaje stan obiektu obserwowanego |
+ | */ | ||
+ | StanObserwowanego podaj_stan() { | ||
+ | //zwroc stan_ | ||
} | } | ||
+ | private: | ||
+ | /** | ||
+ | * opisuje stan obiektu obserwowanego | ||
+ | */ | ||
+ | StanObserwowanego* stan_; | ||
}; | }; | ||
- | //Abstrakcyjny Obserwator | + | </code> |
+ | ====Abstrakcyjny Obserwator==== | ||
+ | <code cpp> | ||
class Obserwator { | class Obserwator { | ||
public: | public: | ||
+ | /** | ||
+ | * powiadamia obserwatora o zajsciu zmiany stanu w obiekcie obserwowanym | ||
+ | */ | ||
virtual void odswiez() = 0; | virtual void odswiez() = 0; | ||
- | virtual ~Obserwator(){} | + | /** |
+ | * abstrakcyjny destruktor | ||
+ | */ | ||
+ | virtual ~Obserwator() { | ||
+ | ; | ||
+ | } | ||
}; | }; | ||
- | //Obserwator konkretny | + | </code> |
+ | ====Obserwator konkretny==== | ||
+ | <code cpp> | ||
class ObserwatorKonkretny : public Obserwator { | class ObserwatorKonkretny : public Obserwator { | ||
public: | public: | ||
+ | /** | ||
+ | * powiadamia obserwatora o zajsciu zmiany stanu w obiekcie obserwowanym | ||
+ | */ | ||
void odswiez() { | void odswiez() { | ||
- | /* uzyskaj aktualny stan obserwowanego */ | + | /* uzyskaj aktualny stan obiektu obserwowanego */ |
} | } | ||
}; | }; | ||
</code> | </code> | ||
- | =====Opis elementów wzorca===== | ||
- | W skład wzorca wchodzą cztery elementy: | ||
- | - **Obserwowany**: Klasa abstrakcyjna dostarczająca interfejs dla dodawania i usuwania obserwatorów, oraz powiadamiania o zmianie stanu wszystkich obserwatorów z listy. Zawiera: | ||
- | * //dodaj//- dodaje obserwatora | ||
- | * //usun//- usuwa obserwatora | ||
- | * //powiadom//- powiadamia o zmianie wszystkich obserwatorow z listy poprzez wołanie metody odswież dla każdego z nich | ||
- | - **Obserwowany Konkretny**: Klasa zwraca swój wewnętrzny stan, który jest obiektem zainteresowania obserwatorów. Powiadamia także swoich obserwatorów na wypadek zmiany swojego stanu. Zawiera: | ||
- | * //podaj_stan// - zwraca aktualny stan obiektu | ||
- | - **Obserwator**: Klasa abstrakcyjna dostarczająca interfejs dla powiadamiania dla wszystkich obserwatorów. Zawiera: | ||
- | * //odswiez// - abstrakcyjna metoda która ma być nadpisana przez konkretnego obserwatora | ||
- | - **Obserwator konkretny**: Klasa pozostaję w związku z obiektem obserwowanym (ObserwowanyKonkretny) aby otrzymać/pobrać jego stan w wypadku powiadomienia o zmienie. Zawiera: | ||
- | * //odswiez// - podczas wołania tej metody (która nadpisuje metode abstrakcyjną w klasie bazowej), konkretny obserwator woła podaj_stan dla obiektu obserwowanego aby zaktualizować informację o nim | ||
=====Typowe użycie===== | =====Typowe użycie===== | ||
Dla przykładu weźmy dwa obiekty **A** oraz **B**, przy czym stan obiektu **A** jest zależny od stanu obiektu **B**, czyli może się zdarzyć że po zmianie stanu obiektu **B** obiekt **A** również powinien zmienić swój stan. W tym ogólnym (i prostym) przypadku można pokusić się o bezpośrednią interakcje pomiędzy obiektami poprzez utrzymanie w jednym z nich wskaźnika lub referencji na drugi. Sytuacja jednak komplikuje się kiedy: | Dla przykładu weźmy dwa obiekty **A** oraz **B**, przy czym stan obiektu **A** jest zależny od stanu obiektu **B**, czyli może się zdarzyć że po zmianie stanu obiektu **B** obiekt **A** również powinien zmienić swój stan. W tym ogólnym (i prostym) przypadku można pokusić się o bezpośrednią interakcje pomiędzy obiektami poprzez utrzymanie w jednym z nich wskaźnika lub referencji na drugi. Sytuacja jednak komplikuje się kiedy: | ||
Linia 73: | Linia 111: | ||
=====Podsumowanie===== | =====Podsumowanie===== | ||
Wzorzec obserwatora pozwala uniknąć niepotrzebnych (nieraz uciążliwych albo niemożliwych) bezpośrednich interakcji pomiędzy obiektami. Przykładem takiej sytuacji jest problem w którym nie znamy ilości obiektów które pozostaną w zależności lub też ilość ta może ulegać zmianie. Przy wykorzystaniu tego wzorca dodawanie i usuwanie obserwatorów nie stanowi problemu. | Wzorzec obserwatora pozwala uniknąć niepotrzebnych (nieraz uciążliwych albo niemożliwych) bezpośrednich interakcji pomiędzy obiektami. Przykładem takiej sytuacji jest problem w którym nie znamy ilości obiektów które pozostaną w zależności lub też ilość ta może ulegać zmianie. Przy wykorzystaniu tego wzorca dodawanie i usuwanie obserwatorów nie stanowi problemu. | ||
+ | |||
W większości przypadków, obserwatorzy zostaną tylko powiadomieni o zmianach. Znaczy to, że sami będą musieli je rozpoznać i ocenić czy ich dotyczą, co jednak może zostać rozwiązane poprzez umieszczanie odpowiedniej informacji w powiadomieniu. | W większości przypadków, obserwatorzy zostaną tylko powiadomieni o zmianach. Znaczy to, że sami będą musieli je rozpoznać i ocenić czy ich dotyczą, co jednak może zostać rozwiązane poprzez umieszczanie odpowiedniej informacji w powiadomieniu. | ||
+ | |||
Obiekty obserwatorów są od siebie zupełnie niezależne, natomiast wszystkie polegają na stanie obiektu obserwowanego, toteż należy zwrócić uwagę na zmiany stanu obiektu obserwowanego jakie mogą zostać wywołane przez obserwatora, zwłaszcza podczas wykonywania przez niego metody //odswiez//. Sytuacja taka pociąga za sobą jeszcze jedno niebezpieczeństwo, otóż jeśli zmiana stanu obiektu obserwowanego następuję w metodzie //odswiez//, bardzo łatwo o kolejne powiadomienie a co za tym idzie kolejne wywołania metody //odswiez// - co w takim wypadku prowadzi do rekurencji. | Obiekty obserwatorów są od siebie zupełnie niezależne, natomiast wszystkie polegają na stanie obiektu obserwowanego, toteż należy zwrócić uwagę na zmiany stanu obiektu obserwowanego jakie mogą zostać wywołane przez obserwatora, zwłaszcza podczas wykonywania przez niego metody //odswiez//. Sytuacja taka pociąga za sobą jeszcze jedno niebezpieczeństwo, otóż jeśli zmiana stanu obiektu obserwowanego następuję w metodzie //odswiez//, bardzo łatwo o kolejne powiadomienie a co za tym idzie kolejne wywołania metody //odswiez// - co w takim wypadku prowadzi do rekurencji. | ||
+ | |||
Jako że nie istnieje jawna interakcja pomiędzy obiektem obserwowany a obserwatorami, łatwo doprowadzić do sytuacji w której obiekt obserwowany przestaje być tym czym był do tej pory (w szczególności zostaje usunięty) bez podania odpowiedniej informacji do obserwatorów. | Jako że nie istnieje jawna interakcja pomiędzy obiektem obserwowany a obserwatorami, łatwo doprowadzić do sytuacji w której obiekt obserwowany przestaje być tym czym był do tej pory (w szczególności zostaje usunięty) bez podania odpowiedniej informacji do obserwatorów. |