Observer Pattern
Part of the Object Oriented Programming section of Coddy's C++ journey — lesson 94 of 104.
The Observer pattern defines a one-to-many dependency between objects: when one object (the subject) changes state, all its dependents (the observers) are notified automatically. This is ideal for event systems, UI updates, or any scenario where multiple objects need to react to changes.
The pattern involves two key roles: a Subject that maintains a list of observers and notifies them, and Observers that implement an update interface:
#include <iostream>
#include <vector>
#include <algorithm>
class Observer {
public:
virtual void update(int value) = 0;
virtual ~Observer() = default;
};
class Subject {
std::vector<Observer*> observers;
int state = 0;
public:
void attach(Observer* obs) {
observers.push_back(obs);
}
void detach(Observer* obs) {
observers.erase(
std::remove(observers.begin(), observers.end(), obs),
observers.end());
}
void setState(int value) {
state = value;
notify();
}
void notify() {
for (Observer* obs : observers) {
obs->update(state);
}
}
};
class Display : public Observer {
std::string name;
public:
Display(const std::string& n) : name(n) {}
void update(int value) override {
std::cout << name << " received: " << value << "\n";
}
};
int main() {
Subject sensor;
Display screen1("Screen1"), screen2("Screen2");
sensor.attach(&screen1);
sensor.attach(&screen2);
sensor.setState(42); // Both displays notified
}When setState() is called, the subject iterates through all registered observers and calls their update() method. Observers can attach or detach at any time, making the system flexible and loosely coupled.
Use Observer when changes to one object require updating others, and you don't want these objects tightly coupled together.
Challenge
EasyLet's build a Weather Station monitoring system using the Observer pattern. You'll create a weather station that tracks temperature data and automatically notifies multiple display units whenever the temperature changes—a classic real-world application of this pattern.
You'll organize your code across three files:
Observer.h: Define the observer interface and a concrete display observer.Create an abstract
Observerclass with a pure virtual methodupdate(double temperature)that observers implement to receive notifications, along with a virtual destructor.Then create a
TemperatureDisplayclass that inherits fromObserver. Each display has a name (string) set through its constructor. Whenupdate()is called, it should print:[DisplayName]: Temperature is [temperature] degreesWeatherStation.h: Create the subject that maintains temperature and notifies observers.Your
WeatherStationclass should:- Store a list of observer pointers and the current temperature (initialize to
0.0) - Have an
attach(Observer* obs)method to register observers - Have a
detach(Observer* obs)method to remove observers - Have a
setTemperature(double temp)method that updates the temperature and notifies all attached observers - Have a private
notify()method that callsupdate()on each observer with the current temperature
- Store a list of observer pointers and the current temperature (initialize to
main.cpp: Demonstrate the Observer pattern in action.Read three inputs:
- Name for the first display (string)
- Name for the second display (string)
- A temperature value (double)
Create a
WeatherStationand twoTemperatureDisplayobjects with the provided names. Attach both displays to the station, then set the temperature to the input value. Both displays should automatically receive the update and print their messages.After that, detach the first display and set a new temperature that is 5 degrees higher than the input. Only the second display should receive this update.
For example, with inputs Kitchen, Bedroom, and 22.5:
Kitchen: Temperature is 22.5 degrees
Bedroom: Temperature is 22.5 degrees
Bedroom: Temperature is 27.5 degreesWith inputs Office, Lobby, and 18.0:
Office: Temperature is 18 degrees
Lobby: Temperature is 18 degrees
Lobby: Temperature is 23 degreesNotice how the Observer pattern creates a loosely coupled system—the weather station doesn't need to know anything about the specific displays, it just notifies whoever is listening. When you detach an observer, it stops receiving updates automatically.
Cheat sheet
The Observer pattern defines a one-to-many dependency where a subject notifies all its observers automatically when its state changes.
The pattern has two key roles:
- Subject: Maintains a list of observers and notifies them of state changes
- Observer: Implements an update interface to receive notifications
Basic implementation:
#include <iostream>
#include <vector>
#include <algorithm>
class Observer {
public:
virtual void update(int value) = 0;
virtual ~Observer() = default;
};
class Subject {
std::vector<Observer*> observers;
int state = 0;
public:
void attach(Observer* obs) {
observers.push_back(obs);
}
void detach(Observer* obs) {
observers.erase(
std::remove(observers.begin(), observers.end(), obs),
observers.end());
}
void setState(int value) {
state = value;
notify();
}
void notify() {
for (Observer* obs : observers) {
obs->update(state);
}
}
};
class Display : public Observer {
std::string name;
public:
Display(const std::string& n) : name(n) {}
void update(int value) override {
std::cout << name << " received: " << value << "\n";
}
};Key methods:
attach(): Registers an observer to receive notificationsdetach(): Removes an observer from the notification listnotify(): Iterates through all observers and calls theirupdate()method
Use Observer when changes to one object require updating others without tight coupling between them.
Try it yourself
#include <iostream>
#include <string>
#include "WeatherStation.h"
using namespace std;
int main() {
// Read inputs
string display1Name, display2Name;
double temperature;
cin >> display1Name;
cin >> display2Name;
cin >> temperature;
// TODO: Create a WeatherStation object
// TODO: Create two TemperatureDisplay objects with the input names
// TODO: Attach both displays to the weather station
// TODO: Set the temperature to the input value
// (Both displays should print their messages)
// TODO: Detach the first display
// TODO: Set temperature to 5 degrees higher than the input
// (Only the second display should print)
return 0;
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesC++ Build & CompilationHeader Files & Source FilesNamespaces & ScopeIntroduction to OOP in C++Classes vs ObjectsThe 'this' PointerMethods (Member Functions)Attributes (Data Members)Ctors & Dtors BasicsRecap - Simple Calculator4Class Properties
Instance vs Static MembersGetters and SettersConst Member FunctionsMutable KeywordStatic Methods and VariablesFriend Functions & ClassesRecap - Bank Account Manager7Inheritance
Basic InheritanceInheritance Access LevelsCtor & Dtor Call OrderMethod OverridingVirtual Functions & VTableMultiple InheritanceVirtual InheritanceRecap - Employee Hierarchy10STL Overview
STL Overview & PhilosophySTL ContainersIteratorsSTL AlgorithmsFunctors & Lambda ExpressionsRecap - Word Frequency13Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory & Abstract FactoryBuilder PatternObserver PatternStrategy Pattern2Memory Management
Stack vs Heap MemoryPointers and ReferencesDynamic Memory (new/delete)Smart Pointers in C++RAII in C++Recap - Dynamic Array Manager5Encapsulation
Access Specifiers in C++Access Specifiers In DepthInformation HidingStruct vs ClassNested & Inner ClassesRecap - Student Records System8Polymorphism
Compile vs Runtime PolymorphFunction OverloadingVirtual Functions RevisitedPure Virtual FunctionsAbstract ClassesInterface Design in C++Dynamic Casting & RTTIRecap - Shape Calculator3Constructors & Destructors
Default ConstructorParameterized ConstructorCopy ConstructorMove ConstructorConstructor Init ListsDelegating ConstructorsDestructor Deep DiveRule of Three / Five / ZeroRecap - String Class6Operator Overloading
Intro to Operator OverloadArithmetic Operator OverloadComparison Operator OverloadStream OperatorsAssignment Operator Overload[] and () Operator OverloadType Conversion OperatorsRecap - Matrix Class9Templates
Function TemplatesClass TemplatesTemplate SpecializationVariadic TemplatesSFINAE & Type Traits BasicsRecap - Generic Container