Trusted answers to developer questions

What is the observer design pattern?

Get Started With Data Science

Learn the fundamentals of Data Science with this free course. Future-proof your career by adding Data Science skills to your toolkit — or prepare to land a job in AI, Machine Learning, or Data Analysis.

The observer design pattern is used when a list of objects needs to be notified about a change that they are observing.

Parts of the pattern

There are two main components of the observer design pattern:

  1. 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.

  2. 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.

UML diagram

svg viewer

Explanation

  1. Whenever an object of a concrete observer is created, it registers itself with the subject by calling register().

  2. The register() method adds the calling observer to the observerList.

  3. An arbitrary private method (e.g., a setter) updates the data of the subject and calls notify().

  4. notify() initiates a for loop which iterates over the observerList and calls update() on each item observer of the list.

  5. Since each concrete observer has its own implementation of the abstract method update(), every registered observer changes its state accordingly (due to polymorphism).

Implementation

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 data
notify(); // 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;
}

RELATED TAGS

observer
design pattern
object oriented
analysis
Copyright ©2024 Educative, Inc. All rights reserved
Did you find this helpful?