The observer design pattern is used when a list of objects needs to be notified about a change that they are observing.
There are two main components of the observer design pattern:
Observer: An abstract class of objects which needs to be informed about certain changes. The concrete implementations of this abstract class register with the subject to receive notifications.
Subject: The data which the observer wants to know belongs to this class. Moreover, this class holds a list of all the registered observers to notify them about changes; the list is automatically updated whenever a new observer registers.
Whenever an object of a concrete observer is created, it registers itself with the subject by calling register()
.
The register()
method adds the calling observer to the observerList
.
An arbitrary private method (e.g., a setter) updates the data of the subject and calls notify()
.
notify()
initiates a for
loop which iterates over the observerList
and calls update()
on each item observer of the list.
Since each concrete observer has its own implementation of the abstract method update()
, every registered observer changes its state accordingly (due to polymorphism).
A <list>
container has been used, in C++, for the list of registered observers.
#include <iostream>#include <list>using namespace std;class Observer;class Subject{private:string winner;list<Observer*> observerList;void notify();public:Subject(){winner = "in progress";}void registerObserver(Observer* o){observerList.push_back(o); // observer added to list}string getWinner(){return winner;}void setWinner(string s){winner = s; // Update datanotify(); // Notify all observers}};class Observer{protected:Subject* mySubject;string prediction;public:Observer(Subject* s, string p){mySubject = s;// Register with the subject:mySubject->registerObserver(this);prediction = p;}// Abstract method (implemented by concrete classes):virtual void update() = 0;};class CasualObserver: public Observer{public:CasualObserver(Subject* s, string p): Observer(s, p){}virtual void update(){// Get data from subject:string w = mySubject->getWinner();// React accordingly:if(w == "in progress"){cout << "Casual observer waiting." << endl;}else if(w != prediction){cout << "Casual: It's okay." << endl;}else{cout << "Casual: I can't believe I won!" << endl;}}};class HardcoreObserver: public Observer{public:HardcoreObserver(Subject* s, string p): Observer(s, p){}void update(){// Get updated data from subject:string w = mySubject->getWinner();// React accordingly:if(w == "in progress"){cout << "Hardcore observer waiting." << endl;}else if(w != prediction){cout << "Hardcore: I can't believe I lost." << endl;}else{cout << "Hardcore: I knew I would win." << endl;}}};void Subject::notify(){list<Observer*>::iterator ptr = observerList.begin();int s = (int)observerList.size();// Call update() of every registered observer:for(int i = 0; i < s; i++){(**ptr).update();ptr++;}}int main(){// Create a subject:Subject game;// Create observers and register them with the game:CasualObserver c(&game, "Team A");HardcoreObserver h(&game, "Team B");// Change game status:game.setWinner("Team B");return 0;}
Free Resources