Observer pattern is used when there is one-to-many relationship between objects such as if one object is modified, its dependent objects are to be notified automatically. The subject that been observed is often known as observable, and when there are changes or updates to the observable, it will notify its observers or sometimes the subscribers.

Applicability

  • When you want object to notify other objects whenever there are changes happen to it.
  • The object should be notifying other objects without knowing what the dependent objects are, or you want to decouple the sender and the receivers.
  • When you have a event driven system or GUI application and you want to handle user interface event. For example, buttons can be observers of mouse click events.
  • You you are working with MVC architecture patterns, the model is the subject, and views are the observers.

Approach

  1. Define the subject, it can be a concrete subject or an interface (observable). The subject have methods to register, remove, and notify observers.
  2. Create an abstraction for the observer, it could be an interface. This interface typically includes an update method to response to the changes in the subject’s state.
  3. Create concrete observers that implement the abstraction, Each concrete observer will provide its own behaviour for handling updates from the subject.

Components

  • Subject
    • The subject is the object that is being observed
    • It maintains a list of observers and has the ability to manage them (subscribe or unsubscribe)
    • The subject should notify its observers when its internal state changes
  • Observer (abstract)
    • The observer is an interface or abstract class that defines the contract for objects that want to be notified of the changes in the subject’s state
    • Typically an update method will be called by the subject when a change occurs.
  • Concrete observer
    • A concrete observer implements the observer interface with the methods defined in interface.
    • Concrete observers implement the update method to define their specific behaviour when notified by the subject.

Example

Identify observer pattern components

Subject: WeatherStation Observer: WeatherObserver Concrete observers: MobileApp, DesktopApp

Subject

The subject WeatherStation has methods to manage its observers, and allows the notification to be sent when there are changes happened, which is when it receives measurements update.

class WeatherStation {
    private List<WeatherObserver> observers = new ArrayList<>();
    private float temperature;
    private float humidity;
    private float pressure;
 
    public void registerObserver(WeatherObserver observer) {
        observers.add(observer);
    }
 
    public void removeObserver(WeatherObserver observer) {
        observers.remove(observer);
    }
 
    public void notifyObservers() {
        for (WeatherObserver observer : observers) {
            observer.update(temperature, humidity, pressure);
        }
    }
 
    // Simulate receiving weather data updates
    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }
 
    private void measurementsChanged() {
        notifyObservers();
    }
}

Observer

The observer interface defines a update method which concrete observer will implement to response to the update.

interface WeatherObserver {
    void update(float temperature, float humidity, float pressure);
}

Concrete observer

MobileApp and DesktopApp are concrete implementations of the WeatherObserver interface. The update method in each concrete observer can have different behaviours that response to the update.

class MobileApp implements WeatherObserver {
    @Override
    public void update(float temperature, float humidity, float pressure) {
        System.out.println("Mobile App: Weather updated - Temperature: " + temperature + "°C, Humidity: " + humidity + "%");
    }
}
class DesktopApp implements WeatherObserver {
    @Override
    public void update(float temperature, float humidity, float pressure) {
        System.out.println("Desktop App: Weather updated - Temperature: " + temperature + "°C, Pressure: " + pressure + " hPa");
    }
}

Application code

public class Demo {
    public static void main(String[] args) {
        // Create subject
        WeatherStation weatherStation = new WeatherStation();
 
        // Create observers 
        WeatherObserver mobileApp = new MobileApp();
        WeatherObserver desktopApp = new DesktopApp();
 
        // Register observers with the weather station
        weatherStation.registerObserver(mobileApp);
        weatherStation.registerObserver(desktopApp);
 
        // Simulate changes in weather data
        weatherStation.setMeasurements(25.5f, 60.0f, 1013.2f);
    }
}
 Mobile App: Weather updated - Temperature: 25.5°C, Humidity: 60.0%
 Desktop App: Weather updated - Temperature: 25.5°C, Pressure: 1013.2 hPa

Back to super node: Behavioural Patterns

Design_PatternBehavioural_Design_PatternsSOFT2201