Menu
Coddy logo textTech

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 icon

Challenge

Easy

Let'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 Observer class with a pure virtual method update(double temperature) that observers implement to receive notifications, along with a virtual destructor.

    Then create a TemperatureDisplay class that inherits from Observer. Each display has a name (string) set through its constructor. When update() is called, it should print:

    [DisplayName]: Temperature is [temperature] degrees
  • WeatherStation.h: Create the subject that maintains temperature and notifies observers.

    Your WeatherStation class 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 calls update() on each observer with the current temperature
  • main.cpp: Demonstrate the Observer pattern in action.

    Read three inputs:

    1. Name for the first display (string)
    2. Name for the second display (string)
    3. A temperature value (double)

    Create a WeatherStation and two TemperatureDisplay objects 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 degrees

With inputs Office, Lobby, and 18.0:

Office: Temperature is 18 degrees
Lobby: Temperature is 18 degrees
Lobby: Temperature is 23 degrees

Notice 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 notifications
  • detach(): Removes an observer from the notification list
  • notify(): Iterates through all observers and calls their update() 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;
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming