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
Subject
Maintains a list of observers.
Provides methods for adding, removing, and notifying observers.
Observer
Defines an interface for objects that need to be notified of changes in the subject.
ConcreteSubject
Implements the subject interface.
Stores state and notifies observers when its state changes.
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
attach(Observer): Registers an observer to the subject.
detach(Observer): Removes an observer from the subject.
notifyObservers(): Notifies all registered observers about a state change.
Advantages
Loose Coupling: The subject and observers are loosely coupled, allowing flexibility and reuse.
Scalability: Easily add or remove observers without modifying the subject.
Real-Time Updates: Observers are notified of state changes immediately.
Disadvantages
Performance Overhead: Notifying a large number of observers can be time-consuming.
Complexity: Managing dependencies between objects can become complex in large systems.
Potential Memory Leaks: Observers might not be removed properly, causing memory issues.
Real-World Examples
Publish-Subscribe Systems: Email or notification systems where subscribers are notified of new updates.
Event Listeners in GUIs: Buttons, text fields, or sliders in graphical user interfaces notify listeners of user actions.
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.