Open In App

Observer Design Pattern

The Observer Design Pattern is a behavioral design pattern that defines a one-to-many dependency between objects so that when one object (the subject) changes state, all its dependents (observers) are notified and updated automatically.



What is the Observer Design Pattern?

The Observer Design Pattern is a behavioral design pattern that defines a one-to-many dependency between objects so that when one object (the subject) changes state, all its dependents (observers) are notified and updated automatically.



It primarily deals with the interaction and communication between objects, specifically focusing on how objects behave in response to changes in the state of other objects.

Real-world analogy of the Observer Design Pattern

Let us Imagine a scenario where the weather station is observed by various smart devices. The weather station maintains a list of registered devices. When there’s a change in weather conditions, the weather station notifies all devices about the update.

Components of Observer Design Pattern

1. Subject

The subject maintains a list of observers (subscribers or listeners). It Provides methods to register and unregister observers dynamically and defines a method to notify observers of changes in its state.

2. Observer

Observer defines an interface with an update method that concrete observers must implement and ensures a common or consistent way for concrete observers to receive updates from the subject. Concrete observers implement this interface, allowing them to react to changes in the subject’s state.

3. ConcreteSubject

ConcreteSubjects are specific implementations of the subject. They hold the actual state or data that observers want to track. When this state changes, concrete subjects notify their observers. For instance, if a weather station is the subject, specific weather stations in different locations would be concrete subjects.

4. ConcreteObserver

Concrete Observer implements the observer interface. They register with a concrete subject and react when notified of a state change. When the subject’s state changes, the concrete observer’s update() method is invoked, allowing it to take appropriate actions. In a practical example, a weather app on your smartphone is a concrete observer that reacts to changes from a weather station.

Observer Design Pattern Example

Consider a scenario where you have a weather monitoring system. Different parts of your application need to be updated when the weather conditions change.

Challenges or difficulties while implementing this system without Observer Design Pattern

How Observer Pattern helps to solve above challenges?

The Observer Pattern helps decouple the weather monitoring system from the components interested in weather updates. Each component can register as an observer, and when the weather changes, the observers are notified. This way, adding or removing components doesn’t affect the weather monitoring system.

Below is the code of above problem statement using Observer Pattern:

1. Subject




public interface Subject {
    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

2. Observer




public interface Observer {
    void update(String weather);
}

3. ConcreteSubject(WeatherStation)




import java.util.ArrayList;
import java.util.List;
 
public class WeatherStation implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String weather;
 
    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }
 
    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }
 
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(weather);
        }
    }
 
    public void setWeather(String newWeather) {
        this.weather = newWeather;
        notifyObservers();
    }
}

4. ConcreteObserver(PhoneDisplay)




public class PhoneDisplay implements Observer {
    private String weather;
 
    @Override
    public void update(String weather) {
        this.weather = weather;
        display();
    }
 
    private void display() {
        System.out.println("Phone Display: Weather updated - " + weather);
    }
}

5. ConcreteObserver(TVDisplay)




/*package whatever //do not write package name here */
 
import java.io.*;
 
class GFG {
    public static void main (String[] args) {
        System.out.println("GFG!");
    }
}

6. Usage




public class WeatherApp {
    public static void main(String[] args) {
        WeatherStation weatherStation = new WeatherStation();
 
        Observer phoneDisplay = new PhoneDisplay();
        Observer tvDisplay = new TVDisplay();
 
        weatherStation.addObserver(phoneDisplay);
        weatherStation.addObserver(tvDisplay);
 
        // Simulating weather change
        weatherStation.setWeather("Sunny");
 
        // Output:
        // Phone Display: Weather updated - Sunny
        // TV Display: Weather updated - Sunny
    }
}

Complete code for the above example

Below is the complete code for the above example:




import java.util.ArrayList;
import java.util.List;
 
// Observer Interface
interface Observer {
    void update(String weather);
}
 
// Subject Interface
interface Subject {
    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}
 
// ConcreteSubject Class
class WeatherStation implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String weather;
 
    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }
 
    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }
 
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(weather);
        }
    }
 
    public void setWeather(String newWeather) {
        this.weather = newWeather;
        notifyObservers();
    }
}
 
// ConcreteObserver Class
class PhoneDisplay implements Observer {
    private String weather;
 
    @Override
    public void update(String weather) {
        this.weather = weather;
        display();
    }
 
    private void display() {
        System.out.println("Phone Display: Weather updated - " + weather);
    }
}
 
// ConcreteObserver Class
class TVDisplay implements Observer {
    private String weather;
 
    @Override
    public void update(String weather) {
        this.weather = weather;
        display();
    }
 
    private void display() {
        System.out.println("TV Display: Weather updated - " + weather);
    }
}
 
// Usage Class
public class WeatherApp {
    public static void main(String[] args) {
        WeatherStation weatherStation = new WeatherStation();
 
        Observer phoneDisplay = new PhoneDisplay();
        Observer tvDisplay = new TVDisplay();
 
        weatherStation.addObserver(phoneDisplay);
        weatherStation.addObserver(tvDisplay);
 
        // Simulating weather change
        weatherStation.setWeather("Sunny");
 
        // Output:
        // Phone Display: Weather updated - Sunny
        // TV Display: Weather updated - Sunny
    }
}




Phone Display: Weather updated - Sunny
TV Display: Weather updated - Sunny

When to use the Observer Design Pattern?

When not to use the Observer Design Pattern?


Article Tags :