Wzorce projektowe (18)
Autor: Damian Chodorek • Opublikowany: 24 lipca 2015 • Kategoria: kursy, wzorce projektowe
Obserwator.
Obserwator to wzorzec obiektowy. Jego celem jest powiadamianie zainteresowanych obiektów o zmianie stanu innego obiektu.
Klasy
class Observable{/*
abstrakcyjna klasa, która definiuje metody odpowiedzialne za dodawanie i usuwanie obserwatorów oraz za powiadamianie zainteresowanych
*/};
class ConcreteObservable: public Observable{/*
klasa konkretnych obiektów obserwowanych, jeśli któryś zmieni swój stan, powiadomi o tym wszystkich obserwujących
*/};
class Observer{/*
abstrakcyjna klasa deklarująca aktualizację własnego stanu
*/};
class ConcreteObserver: public Observer{/*
konkretny obserwator, definiuje metodę odpowiadającą za aktualizację swojego stanu
*/};
Etapy działania
- Klient tworzy obserwowanego i obserwujących.
- Do obiektu obserwowanego podpina obiekty obserwujących.
- Jeśli obiekt obserwowany zmieni swój stan, powiadomi o tym podpiętych obserwujących.
- Reakcja na powiadomienie należy do samych obserwujących.
Konsekwencje
Zalety:
- ponieważ obiekt obserwujący i obserwowany nie wiedzą wiele o sobie nawzajem, mogą być niezależnie modyfikowane,
- relacja między obserwatorem i obserwowanym tworzona jest podczas działania programu i może być zmieniana
dynamicznie, - domyślnie obserwowany powiadamia wszystkich obserwatorów; oni sami decydują czy obsłużyć fakt powiadomienia.
Wady:
- Obserwatorzy nie znają innych obserwatorów, to może wywołać trudne do znalezienia skutki uboczne.
Przykład
#include <iostream>
#include <string>
#include <list>
using namespace std;
//Obserwator:
class Observer {
public:
virtual void update() = 0;
virtual ~Observer() {}
};
//Obserwowany:
class Observable {
protected:
list <Observer*> observers;
public:
void attach (Observer *o) {
observers.push_back (o);
}
void detach (Observer *o) {
observers.remove (o);
}
void notify () {
list<Observer *>::iterator it;
for (it = observers.begin(); it != observers.end(); it++) {
(*it)->update ();
}
}
};
//Obserwowany Konkretny:
class Honey {
protected:
int quantity;
public:
Honey (int q) {
quantity = q;
}
int getQuantity () {
return quantity;
}
void setQuantity (int q) {
quantity = q;
}
};
// wielokrotne dziedziczenie jest często wykorzystywane w tym wzorcu
class ObservableHoney : public Observable, public Honey {
string state;
public:
ObservableHoney (int q) : Honey(q) {
}
string getState () {
return state;
}
void setState (const string& s) {
state = s;
cout << "Stan: " << state << endl;
notify();
}
};
//Obserwator Konkretny:
class ObserverBear : public Observer {
protected:
int bearId;
ObservableHoney *honey;
public:
ObserverBear (ObservableHoney *h, int id) {
honey = h;
bearId = id;
}
void update () {
string state = honey->getState();
if (!state.compare ("Sa ludzie blisko miodu")) {
cout << "Mis" << bearId << ": Czekam w ukryciu" << endl;
} else if (!state.compare ("Nie ma ludzi blisko miodu")) {
cout << "Mis" << bearId << ": Kradne miod" << endl;
honey->setQuantity(honey->getQuantity()-1);
} else if (!state.compare ("Ida ludzie")) {
cout << "Mis" << bearId << ": Uciekam" << endl;
}
}
};
//Przyklad uzycia:
int main() {
ObservableHoney honey (5);
Observer *bear1 = new ObserverBear(&honey, 1);
Observer *bear2 = new ObserverBear(&honey, 2);
honey.attach(bear1);
honey.attach(bear2);
cout << "Ilosc miodu: " << honey.getQuantity() << endl;
honey.setState("Sa ludzie blisko miodu");
honey.setState("Nie ma ludzi blisko miodu");
honey.setState("Ida ludzie");
cout << "Ilosc miodu: " << honey.getQuantity() << endl;
delete bear1;
delete bear2;
return 0;
}