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
- Observer Interface:
- The
Observer
interface defines theupdate()
method, which will be called by the subject when its state changes.
- Subject Interface:
- The
Subject
interface defines methods for registering, removing, and notifying observers.
- WeatherStation (Concrete Subject):
- The
WeatherStation
class implements theSubject
interface. It maintains a list of observers and notifies them whenever its weather data changes. ThesetWeatherData()
method simulates changes in temperature and humidity, which triggers thenotifyObservers()
method to update all observers.
- Concrete Observers:
- CurrentConditionsDisplay: Displays the current temperature and humidity.
- StatisticsDisplay: Displays the average, maximum, and minimum temperatures recorded over time.
- Main Class:
- In the
main()
method, we create instances ofWeatherStation
and the two displays (CurrentConditionsDisplay
andStatisticsDisplay
). 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.