Observer Design Pattern

Last Updated : 7 May, 2026

Observer Design Pattern is a behavioral pattern that creates a one-to-many relationship between a subject and its observers. When the subject's state changes, all dependent observers are notified and updated automatically, ensuring synchronized communication.

  • Enables automatic updates to multiple objects when one object changes, useful for event-driven or publish-subscribe systems.
  • Promotes loose coupling between the subject and its observers, improving flexibility and maintainability.

Example: A YouTube channel (Subject) notifies all its subscribers (Observers) whenever a new video is uploaded.

observer-design-Pattern
Observer Design Pattern

In the Diagram

  • Clients (A, B, C) interact with the Subject, and when its state changes, it triggers a notification.
  • The Subject sends notify() updates to all registered Observers (Observer 1, 2, 3).
  • Observers automatically receive updates and react, without the Subject knowing their specific details (loose coupling).

Note: Subjects are the objects that maintain and notify observers about changes in their state, while Observers are the entities that react to those changes.

Real-Life Applications

The Observer pattern is widely used in applications where changes in one object need to be automatically reflected in multiple others:

  • Social Media Notifications: Users (observers) receive updates when someone they follow (subject) posts new content.
  • Stock Market Apps: Investors get real-time updates when stock prices (subjects) change.
  • Event Listeners in GUIs: UI components respond to user actions like clicks or keyboard input.
  • Weather Monitoring Systems: Multiple displays update automatically when central weather data changes.

Components

The main components of Observer Design Pattern are:

class_diagram_of_observer_design_pattern
Class Diagram
  • Subject: Maintains a list of observers, provides methods to add/remove them, and notifies them of state changes.
  • Observer: Defines an interface with an update() method to ensure all observers receive updates consistently.
  • ConcreteSubject: A specific subject that holds actual data. On state change, it notifies registered observers (e.g., a weather station).
  • ConcreteObserver: Implements the observer interface and reacts to subject updates (e.g., a weather app showing weather updates).

Working

The Observer Pattern works by establishing a subscription mechanism between a subject and its observers so that changes in one object are automatically reflected in others.

  • Observers subscribe to the subject to receive updates.
  • The subject maintains a list of registered observers.
  • When the subject’s state changes, it notifies all observers.
  • Observers react to the update according to their own behavior.

Uses

The Observer Pattern is used when multiple objects need to be notified automatically about changes in another object’s state.

  • To implement event handling systems such as GUI listeners.
  • To maintain consistency between related objects without tight coupling.
  • To support publish–subscribe mechanisms.

Implementation Example

Problem statement

Imagine a weather monitoring system where multiple display devices like phone and TV need to show updated weather information. Whenever the weather changes, all devices should receive updates automatically without being tightly connected to the weather system.

The Observer pattern solves this by allowing devices (observers) to register with a WeatherStation (subject). When the weather changes using setWeather(), it notifies all observers, and they update their display accordingly.

1. Subject

  • The "Subject" interface outlines the operations a subject (like "WeatherStation") should support.
  • "addObserver" and "removeObserver" are for managing the list of observers.
  • "notifyObservers" is for informing observers about changes.
C++
public interface Subject {
    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}
Java
public interface Subject {
    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}
Python
from abc import ABC, abstractmethod

class Subject(ABC):
    @abstractmethod
    def add_observer(self, observer):
        pass

    @abstractmethod
    def remove_observer(self, observer):
        pass

    @abstractmethod
    def notify_observers(self):
        pass
JavaScript
class Subject {
    addObserver(observer) {
        // Implementation
    }

    removeObserver(observer) {
        // Implementation
    }

    notifyObservers() {
        // Implementation
    }
}

2. Observer

  • The "Observer" interface defines a contract for objects that want to be notified about changes in the subject ("WeatherStation" in this case).
  • It includes a method "update"that concrete observers must implement to receive and handle updates.
C++
public interface Observer {
    void update(String weather);
}
Java
public interface Observer {
    void update(String weather);
}
Python
from abc import ABC, abstractmethod

class Observer(ABC):
    @abstractmethod
    def update(self, weather: str):
        pass
JavaScript
class Observer {
    update(weather) {
        // Implementation here
    }
}

3. ConcreteSubject(WeatherStation)

  • "WeatherStation" is the concrete subject implementing the "Subject" interface.
  • It maintains a list of observers ("observers") and provides methods to manage this list.
  • "notifyObservers" iterates through the observers and calls their "update" method, passing the current weather.
  • "setWeather" method updates the weather and notifies observers of the change.
C++
#include <vector>
#include <string>
#include <algorithm>

class Observer {
public:
    virtual void update(const std::string& weather) = 0;
};

class Subject {
public:
    virtual void addObserver(Observer* observer) = 0;
    virtual void removeObserver(Observer* observer) = 0;
    virtual void notifyObservers() = 0;
};

class WeatherStation : public Subject {
private:
    std::vector<Observer*> observers;
    std::string weather;

public:
    void addObserver(Observer* observer) override {
        observers.push_back(observer);
    }

    void removeObserver(Observer* observer) override {
        observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
    }

    void notifyObservers() override {
        for (Observer* observer : observers) {
            observer->update(weather);
        }
    }

    void setWeather(const std::string& newWeather) {
        this->weather = newWeather;
        notifyObservers();
    }
};
Java
import java.util.ArrayList;
import java.util.List;

// Observer interface
interface Observer {
    void update(String weather);
}

// Subject interface
interface Subject {
    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// Concrete Subject
class WeatherStation implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String weather = "";

    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(weather);
        }
    }

    public void setWeather(String newWeather) {
        this.weather = newWeather;
        notifyObservers();
    }
}
Python
from abc import ABC, abstractmethod
from typing import List

class Observer(ABC):
    @abstractmethod
    def update(self, weather: str):
        pass

class Subject(ABC):
    @abstractmethod
    def add_observer(self, observer: Observer):
        pass

    @abstractmethod
    def remove_observer(self, observer: Observer):
        pass

    @abstractmethod
    def notify_observers(self):
        pass

class WeatherStation(Subject):
    def __init__(self):
        self.observers: List[Observer] = []
        self.weather = ""

    def add_observer(self, observer: Observer):
        self.observers.append(observer)

    def remove_observer(self, observer: Observer):
        if observer in self.observers:
            self.observers.remove(observer)

    def notify_observers(self):
        for observer in self.observers:
            observer.update(self.weather)

    def set_weather(self, new_weather: str):
        self.weather = new_weather
        self.notify_observers()
JavaScript
class Observer {
    update(weather) {
        throw new Error('Method update() must be implemented.');
    }
}

class Subject {
    addObserver(observer) {
        throw new Error('Method addObserver() must be implemented.');
    }
    removeObserver(observer) {
        throw new Error('Method removeObserver() must be implemented.');
    }
    notifyObservers() {
        throw new Error('Method notifyObservers() must be implemented.');
    }
}

class WeatherStation extends Subject {
    constructor() {
        super();
        this.observers = [];
        this.weather = "";
    }
    addObserver(observer) {
        this.observers.push(observer);
    }
    removeObserver(observer) {
        this.observers = this.observers.filter(obs => obs !== observer);
    }
    notifyObservers() {
        this.observers.forEach(observer => observer.update(this.weather));
    }
    setWeather(newWeather) {
        this.weather = newWeather;
        this.notifyObservers();
    }
}

4. ConcreteObserver(PhoneDisplay)

  • "PhoneDisplay" is a concrete observer implementing the "Observer" interface.
  • It has a private field weather to store the latest weather.
  • The "update" method sets the new weather and calls the "display" method.
  • "display" prints the updated weather to the console.
C++
public class PhoneDisplay implements Observer {
    private String weather;

    @Override
    public void update(String weather) {
        this.weather = weather;
        display();
    }

    private void display() {
        System.out.println("Phone Display: Weather updated - " + weather);
    }
}
Java
import java.util.Observer;
import java.util.Observable;

public class PhoneDisplay implements Observer {
    private String weather;

    @Override
    public void update(Observable o, Object arg) {
        if (arg instanceof String) {
            this.weather = (String) arg;
            display();
        }
    }

    private void display() {
        System.out.println("Phone Display: Weather updated - " + weather);
    }
}
Python
from abc import ABC, abstractmethod

class Observer(ABC):
    @abstractmethod
    def update(self, weather):
        pass

class PhoneDisplay(Observer):
    def __init__(self):
        self.weather = ""

    def update(self, weather):
        self.weather = weather
        self.display()

    def display(self):
        print(f'Phone Display: Weather updated - {self.weather}')
JavaScript
class Observer {
    update(weather) {
        throw new Error('Method not implemented.');
    }
}

class PhoneDisplay extends Observer {
    constructor() {
        super();
        this.weather = "";
    }

    update(weather) {
        this.weather = weather;
        this.display();
    }

    display() {
        console.log(`Phone Display: Weather updated - ${this.weather}`);
    }
}

5. ConcreteObserver(TVDisplay)

  • "TVDisplay" is another concrete observer similar to "PhoneDisplay".
  • It also implements the "Observer" interface, with a similar structure to "PhoneDisplay".
C++
class TVDisplay implements Observer {
    private String weather;
 
    @Override
    public void update(String weather) {
        this.weather = weather;
        display();
    }
 
    private void display() {
        System.out.println("TV Display: Weather updated - " + weather);
    }
}
Java
class TVDisplay implements Observer {
    private String weather;
    
    @Override
    public void update(String weather) {
        this.weather = weather;
        display();
    }
    
    private void display() {
        System.out.println("TV Display: Weather updated - " + weather);
    }
}
Python
class TVDisplay:
    def __init__(self):
        self.weather = ""
    
    def update(self, weather):
        self.weather = weather
        self.display()
    
    def display(self):
        print(f'TV Display: Weather updated - {self.weather}')
JavaScript
class TVDisplay {
    constructor() {
        this.weather = "";
    }
    
    update(weather) {
        this.weather = weather;
        this.display();
    }
    
    display() {
        console.log(`TV Display: Weather updated - ${this.weather}`);
    }
}

6. Usage

  • In "WeatherApp", a "WeatherStation" is created.
  • Two observers ("PhoneDisplay" and "TVDisplay") are registered with the weather station using "addObserver".
  • The "setWeather" method simulates a weather change to "Sunny," triggering the "update" method in both observers.
  • The output shows how both concrete observers display the updated weather information.
C++
public class WeatherApp {
    public static void main(String[] args) {
        WeatherStation weatherStation = new WeatherStation();

        Observer phoneDisplay = new PhoneDisplay();
        Observer tvDisplay = new TVDisplay();

        weatherStation.addObserver(phoneDisplay);
        weatherStation.addObserver(tvDisplay);

        // Simulating weather change
        weatherStation.setWeather("Sunny");

        // Output:
        // Phone Display: Weather updated - Sunny
        // TV Display: Weather updated - Sunny
    }
}
Java
public class WeatherApp {
    public static void main(String[] args) {
        WeatherStation weatherStation = new WeatherStation();

        Observer phoneDisplay = new PhoneDisplay();
        Observer tvDisplay = new TVDisplay();

        weatherStation.addObserver(phoneDisplay);
        weatherStation.addObserver(tvDisplay);

        // Simulating weather change
        weatherStation.setWeather("Sunny");

    }
}
Python
from abc import ABC, abstractmethod

class Observer(ABC):
    @abstractmethod
    def update(self, weather):
        pass

class PhoneDisplay(Observer):
    def update(self, weather):
        print(f'Phone Display: Weather updated - {weather}')

class TVDisplay(Observer):
    def update(self, weather):
        print(f'TV Display: Weather updated - {weather}')

class WeatherStation:
    def __init__(self):
        self.observers = []
        self.weather = ""

    def add_observer(self, observer):
        self.observers.append(observer)

    def set_weather(self, weather):
        self.weather = weather
        self.notify_observers()

    def notify_observers(self):
        for observer in self.observers:
            observer.update(self.weather)

# Main execution
weather_station = WeatherStation()

phone_display = PhoneDisplay()
tv_display = TVDisplay()

weather_station.add_observer(phone_display)
weather_station.add_observer(tv_display)

# Simulating weather change
weather_station.set_weather('Sunny')

# Output:
# Phone Display: Weather updated - Sunny
# TV Display: Weather updated - Sunny
JavaScript
class Observer {
    update(weather) {
        throw new Error('Method not implemented.');
    }
}

class PhoneDisplay extends Observer {
    update(weather) {
        console.log(`Phone Display: Weather updated - ${weather}`);
    }
}

class TVDisplay extends Observer {
    update(weather) {
        console.log(`TV Display: Weather updated - ${weather}`);
    }
}

class WeatherStation {
    constructor() {
        this.observers = [];
        this.weather = "";
    }

    addObserver(observer) {
        this.observers.push(observer);
    }

    setWeather(weather) {
        this.weather = weather;
        this.notifyObservers();
    }

    notifyObservers() {
        this.observers.forEach(observer => observer.update(this.weather));
    }
}

// Main execution
const weatherStation = new WeatherStation();

const phoneDisplay = new PhoneDisplay();
const tvDisplay = new TVDisplay();

weatherStation.addObserver(phoneDisplay);
weatherStation.addObserver(tvDisplay);

// Simulating weather change
weatherStation.setWeather('Sunny');

// Output:
// Phone Display: Weather updated - Sunny
// TV Display: Weather updated - Sunny

Complete code for the above example

The complete code for the above example is:

C++
#include <iostream>
#include <vector>
#include <algorithm> // for std::remove
#include <string>
using namespace std;

// Observer Interface
class Observer {
public:
    virtual void update(const string& weather) = 0;
    virtual ~Observer() {}
};

// Subject Interface
class Subject {
public:
    virtual void addObserver(Observer* observer) = 0;
    virtual void removeObserver(Observer* observer) = 0;
    virtual void notifyObservers() = 0;
    virtual ~Subject() {}
};

// ConcreteSubject Class
class WeatherStation : public Subject {
private:
    vector<Observer*> observers; // list of observers
    string weather;

public:
    void addObserver(Observer* observer) override {
        observers.push_back(observer);
    }

    void removeObserver(Observer* observer) override {
        observers.erase(remove(observers.begin(), observers.end(), observer), observers.end());
    }

    void notifyObservers() override {
        for (Observer* observer : observers) {
            observer->update(weather);
        }
    }

    void setWeather(const string& newWeather) {
        weather = newWeather;
        notifyObservers();
    }
};

// ConcreteObserver Class: PhoneDisplay
class PhoneDisplay : public Observer {
private:
    string weather;

    void display() {
        cout << "Phone Display: Weather updated - " << weather << endl;
    }

public:
    void update(const string& weather) override {
        this->weather = weather;
        display();
    }
};

// ConcreteObserver Class: TVDisplay
class TVDisplay : public Observer {
private:
    string weather;

    void display() {
        cout << "TV Display: Weather updated - " << weather << endl;
    }

public:
    void update(const string& weather) override {
        this->weather = weather;
        display();
    }
};

// Usage / Demo
int main() {
    WeatherStation weatherStation;

    PhoneDisplay phoneDisplay;
    TVDisplay tvDisplay;

    // Register observers
    weatherStation.addObserver(&phoneDisplay);
    weatherStation.addObserver(&tvDisplay);

    // Simulating weather changes
    weatherStation.setWeather("Sunny");
    weatherStation.setWeather("Rainy");
    weatherStation.setWeather("Cloudy");

    // Remove one observer
    weatherStation.removeObserver(&tvDisplay);

    // Notify remaining observer
    weatherStation.setWeather("Windy");

    return 0;
}
Java
import java.util.ArrayList;
import java.util.List;

// Observer Interface
interface Observer {
    void update(String weather);
}

// Subject Interface
interface Subject {
    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// ConcreteSubject Class
class WeatherStation implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String weather;

    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(weather);
        }
    }

    public void setWeather(String newWeather) {
        this.weather = newWeather;
        notifyObservers();
    }
}

// ConcreteObserver Class
class PhoneDisplay implements Observer {
    private String weather;

    @Override
    public void update(String weather) {
        this.weather = weather;
        display();
    }

    private void display() {
        System.out.println("Phone Display: Weather updated - " + weather);
    }
}

// ConcreteObserver Class
class TVDisplay implements Observer {
    private String weather;

    @Override
    public void update(String weather) {
        this.weather = weather;
        display();
    }

    private void display() {
        System.out.println("TV Display: Weather updated - " + weather);
    }
}

// Usage Class
public class WeatherApp {
    public static void main(String[] args) {
        WeatherStation weatherStation = new WeatherStation();

        Observer phoneDisplay = new PhoneDisplay();
        Observer tvDisplay = new TVDisplay();

        // Register observers
        weatherStation.addObserver(phoneDisplay);
        weatherStation.addObserver(tvDisplay);

        // Simulating weather changes
        weatherStation.setWeather("Sunny");
        weatherStation.setWeather("Rainy");
        weatherStation.setWeather("Cloudy");

        // Remove one observer
        weatherStation.removeObserver(tvDisplay);

        // Notify remaining observer
        weatherStation.setWeather("Windy");
    }
}
Python
from abc import ABC, abstractmethod
from typing import List

# Observer Interface
class Observer(ABC):
    @abstractmethod
    def update(self, weather: str):
        pass

# Subject Interface
class Subject(ABC):
    @abstractmethod
    def add_observer(self, observer: Observer):
        pass

    @abstractmethod
    def remove_observer(self, observer: Observer):
        pass

    @abstractmethod
    def notify_observers(self):
        pass

# ConcreteSubject Class
class WeatherStation(Subject):
    def __init__(self):
        self.observers: List[Observer] = []
        self.weather = ""

    def add_observer(self, observer: Observer):
        self.observers.append(observer)

    def remove_observer(self, observer: Observer):
        self.observers.remove(observer)

    def notify_observers(self):
        for observer in self.observers:
            observer.update(self.weather)

    def set_weather(self, new_weather: str):
        self.weather = new_weather
        self.notify_observers()

# ConcreteObserver Class
class PhoneDisplay(Observer):
    def __init__(self):
        self.weather = ""

    def update(self, weather: str):
        self.weather = weather
        self.display()

    def display(self):
        print(f'Phone Display: Weather updated - {self.weather}')

# ConcreteObserver Class
class TVDisplay(Observer):
    def __init__(self):
        self.weather = ""

    def update(self, weather: str):
        self.weather = weather
        self.display()

    def display(self):
        print(f'TV Display: Weather updated - {self.weather}')

# Usage
if __name__ == '__main__':
    weather_station = WeatherStation()

    phone_display = PhoneDisplay()
    tv_display = TVDisplay()

    weather_station.add_observer(phone_display)
    weather_station.add_observer(tv_display)

    # Simulating weather change
    weather_station.set_weather('Sunny')
    # Output:
    # Phone Display: Weather updated - Sunny
    # TV Display: Weather updated - Sunny
JavaScript
// Observer Interface
class Observer {
    update(weather) {
        throw new Error('Method not implemented.');
    }
}

// Subject Interface
class Subject {
    addObserver(observer) {
        throw new Error('Method not implemented.');
    }

    removeObserver(observer) {
        throw new Error('Method not implemented.');
    }

    notifyObservers() {
        throw new Error('Method not implemented.');
    }
}

// ConcreteSubject Class
class WeatherStation extends Subject {
    constructor() {
        super();
        this.observers = [];
        this.weather = "";
    }

    addObserver(observer) {
        this.observers.push(observer);
    }

    removeObserver(observer) {
        this.observers = this.observers.filter(obs => obs !== observer);
    }

    notifyObservers() {
        this.observers.forEach(observer => observer.update(this.weather));
    }

    setWeather(newWeather) {
        this.weather = newWeather;
        this.notifyObservers();
    }
}

// ConcreteObserver Class
class PhoneDisplay extends Observer {
    constructor() {
        super();
        this.weather = "";
    }

    update(weather) {
        this.weather = weather;
        this.display();
    }

    display() {
        console.log(`Phone Display: Weather updated - ${this.weather}`);
    }
}

// ConcreteObserver Class
class TVDisplay extends Observer {
    constructor() {
        super();
        this.weather = "";
    }

    update(weather) {
        this.weather = weather;
        this.display();
    }

    display() {
        console.log(`TV Display: Weather updated - ${this.weather}`);
    }
}

// Usage
const weatherStation = new WeatherStation();

const phoneDisplay = new PhoneDisplay();
const tvDisplay = new TVDisplay();

weatherStation.addObserver(phoneDisplay);
weatherStation.addObserver(tvDisplay);

// Simulating weather change
weatherStation.setWeather('Sunny');
// Output:
// Phone Display: Weather updated - Sunny
// TV Display: Weather updated - Sunny

Output
Phone Display: Weather updated - Sunny
TV Display: Weather updated - Sunny
Phone Display: Weather updated - Rainy
TV Display: Weather updated - Rainy
Phone Display: Weather updated - Cloudy
TV Display...

Advantages

The Observer Pattern improves flexibility and communication between objects.

  • Provides loose coupling between subject and observers.
  • Allows easy addition or removal of observers at runtime.
  • Ensures automatic and consistent updates to all dependents.

Disadvantages

Despite its benefits, the Observer Pattern has some drawbacks.

  • Can lead to performance issues if there are many observers.
  • Debugging becomes harder due to indirect communication.
  • Observers may receive unnecessary updates if not managed carefully.
Comment

Explore