How to Implement Observer Design Pattern in Java

The Observer Design Pattern is a behavioral design pattern that defines a one-to-many relationship between objects. When one object (the Subject) changes state, all its dependents (the Observers) are notified and updated automatically. This pattern is useful for implementing distributed event-handling systems, where multiple components need to be informed of state changes in another component.

Example: Observer Design Pattern in Java

In this example, we will implement a weather station that updates multiple displays whenever the weather data (like temperature and humidity) changes.

Step 1: Define the Observer Interface

// Observer.java
public interface Observer {
    void update(float temperature, float humidity);
}

Step 2: Define the Subject Interface

// Subject.java
public interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}

Step 3: Implement the WeatherStation (Subject)

import java.util.ArrayList;
import java.util.List;

// WeatherStation.java
public class WeatherStation implements Subject {
    private List observers;
    private float temperature;
    private float humidity;

    public WeatherStation() {
        observers = new ArrayList<>();
    }

    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }

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

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

    public void setWeatherData(float temperature, float humidity) {
        this.temperature = temperature;
        this.humidity = humidity;
        notifyObservers();  // Notify all observers when data changes
    }
}

Step 4: Implement the Concrete Observer Classes

// CurrentConditionsDisplay.java
public class CurrentConditionsDisplay implements Observer {
    private float temperature;
    private float humidity;

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

    public void display() {
        System.out.println("Current conditions: " + temperature + "°C and " + humidity + "% humidity.");
    }
}
// StatisticsDisplay.java
public class StatisticsDisplay implements Observer {
    private float maxTemperature = Float.MIN_VALUE;
    private float minTemperature = Float.MAX_VALUE;
    private float sumTemperature = 0;
    private int numReadings = 0;

    @Override
    public void update(float temperature, float humidity) {
        if (temperature > maxTemperature) {
            maxTemperature = temperature;
        }

        if (temperature < minTemperature) {
            minTemperature = temperature;
        }

        sumTemperature += temperature;
        numReadings++;

        display();
    }

    public void display() {
        System.out.println("Avg/Max/Min temperature = " + (sumTemperature / numReadings)
                + "/" + maxTemperature + "/" + minTemperature);
    }
}

Step 5: Using the Observer Pattern in the Main Class

// Main.java
public class Main {
    public static void main(String[] args) {
        WeatherStation weatherStation = new WeatherStation();

        CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay();
        StatisticsDisplay statisticsDisplay = new StatisticsDisplay();

        // Register the observers with the subject
        weatherStation.registerObserver(currentDisplay);
        weatherStation.registerObserver(statisticsDisplay);

        // Simulate weather data changes
        weatherStation.setWeatherData(25.0f, 65.0f);
        weatherStation.setWeatherData(27.5f, 70.0f);
        weatherStation.setWeatherData(23.0f, 60.0f);
    }
}

Explanation of the Code

  1. Observer Interface:
  • The Observer interface defines the update() method, which will be called by the subject when its state changes.
  1. Subject Interface:
  • The Subject interface defines methods for registering, removing, and notifying observers.
  1. WeatherStation (Concrete Subject):
  • The WeatherStation class implements the Subject interface. It maintains a list of observers and notifies them whenever its weather data changes. The setWeatherData() method simulates changes in temperature and humidity, which triggers the notifyObservers() method to update all observers.
  1. Concrete Observers:
  • CurrentConditionsDisplay: Displays the current temperature and humidity.
  • StatisticsDisplay: Displays the average, maximum, and minimum temperatures recorded over time.
  1. Main Class:
  • In the main() method, we create instances of WeatherStation and the two displays (CurrentConditionsDisplay and StatisticsDisplay). We register the displays with the weather station as observers. When the weather data changes, both observers are automatically notified and display the updated data.

Output

When you run the Main class, the output will be:

Current conditions: 25.0°C and 65.0% humidity.
Avg/Max/Min temperature = 25.0/25.0/25.0
Current conditions: 27.5°C and 70.0% humidity.
Avg/Max/Min temperature = 26.25/27.5/25.0
Current conditions: 23.0°C and 60.0% humidity.
Avg/Max/Min temperature = 25.166666/27.5/23.0

Key Points

  • The Observer design pattern allows you to create a one-to-many relationship between objects, where changes in one object automatically update its dependent objects.
  • This pattern helps to decouple the subject and observers, as the subject doesn’t need to know the specific types of the observers.
  • New observer types can be added easily without modifying the subject, making the system flexible and extensible.

Conclusion

The Observer Design Pattern is useful in scenarios where multiple components need to be updated in response to changes in another component. It is commonly used in event-driven systems, GUI frameworks, and in situations where distributed event-handling is required.

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *