08 Jan 2025

Observer Pattern

Overview

The Observer Pattern is a behavioral design pattern that establishes a one-to-many dependency between objects. When the state of one object (the subject) changes, all its dependent objects (observers) are notified automatically. It is widely used to implement event-driven systems.

Key Participants

  1. Subject

  • Maintains a list of observers.

  • Provides methods for adding, removing, and notifying observers.

  1. Observer

  • Defines an interface for objects that need to be notified of changes in the subject.

  1. ConcreteSubject

  • Implements the subject interface.

  • Stores state and notifies observers when its state changes.

  1. ConcreteObserver

  • Implements the observer interface.

  • Updates itself based on notifications from the subject.

Implementation in Code

Example: Weather Monitoring System

// Observer Interface
interface Observer {
    void update(float temperature, float humidity, float pressure);
}

// Subject Interface
interface Subject {
    void attach(Observer observer);
    void detach(Observer observer);
    void notifyObservers();
}

// ConcreteSubject
class WeatherData implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private float temperature;
    private float humidity;
    private float pressure;

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

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

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temperature, humidity, pressure);
        }
    }

    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        notifyObservers();
    }
}

// ConcreteObserver
class CurrentConditionsDisplay implements Observer {
    private float temperature;
    private float humidity;

    @Override
    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        display();
    }

    public void display() {
        System.out.println("Current conditions: " + temperature + "°C and " + humidity + "% humidity");
    }
}

// Client
public class ObserverPatternDemo {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();

        CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay();

        weatherData.attach(currentDisplay);

        weatherData.setMeasurements(25.5f, 65.0f, 1013.0f);
        weatherData.setMeasurements(27.0f, 70.0f, 1012.5f);
    }
}

Key Methods

  1. attach(Observer): Registers an observer to the subject.

  1. detach(Observer): Removes an observer from the subject.

  1. notifyObservers(): Notifies all registered observers about a state change.

Advantages

  1. Loose Coupling: The subject and observers are loosely coupled, allowing flexibility and reuse.

  1. Scalability: Easily add or remove observers without modifying the subject.

  1. Real-Time Updates: Observers are notified of state changes immediately.

Disadvantages

  1. Performance Overhead: Notifying a large number of observers can be time-consuming.

  1. Complexity: Managing dependencies between objects can become complex in large systems.

  1. Potential Memory Leaks: Observers might not be removed properly, causing memory issues.

Real-World Examples

  1. Publish-Subscribe Systems: Email or notification systems where subscribers are notified of new updates.

  1. Event Listeners in GUIs: Buttons, text fields, or sliders in graphical user interfaces notify listeners of user actions.

  1. Stock Market Applications: Investors (observers) are notified of stock price changes (subject).

When to Use the Observer Pattern?

  • When changes in one object require corresponding changes in other objects, without tightly coupling them.

  • When you need to implement a publish-subscribe mechanism.

  • When multiple objects need to be notified of state changes in a single object.

← Back to Library