Open In App

Observer Method Design Pattern in Java

Last Updated : 06 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Observer Design Pattern is a behavioral design pattern where an object, known as the subject, maintains a list of its dependents, called observers, that are notified of any changes in the subject’s state. This pattern is often used to implement distributed event handling systems.

How We can implement the Observer Method Design Pattern in Java?

Basically, in Java, the Observer pattern is implemented using the ‘java.util.Observer’ interface and the ‘java.util.Observable’ class. However, it’s important to note that the Observable class is considered somewhat outdated, and the ‘java.util’ package doesn’t provide a modern and flexible implementation of the Observer pattern.

In other words, the Observer Pattern is a behavioral design pattern that defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. This pattern is commonly used to implement distributed event handling systems.

Key Concepts of Observer Method Design Pattern

The key concepts of the Observer Pattern are:

  • Subject: The subject is the object that maintains a list of its dependents, also known as observers.It provides an interface for attaching, detaching, and notifying observers.
  • Observer: The observer is the interface that defines the update method, which is called by the subject to notify the observer of a change in the subject’s state.Observers register themselves with the subject to receive updates.
  • ConcreteSubject: The concrete subject is a concrete implementation of the subject interface. It maintains the state of interest and notifies observers when a change occurs.
  • ConcreteObserver: The concrete observer is a concrete implementation of the observer interface. It registers itself with a subject to receive updates and implements the update method to respond to changes in the subject’s state.
  • Observer List:The subject maintains a list (or collection) of observers, allowing multiple observers to be notified of changes.
  • Loose Coupling: The Observer Pattern promotes loose coupling between the subject and its observers. The subject doesn’t need to know the details of its observers, and observers can be added or removed without affecting the subject.

Example for Observer Method Design Pattern in Java

Problem Statement

Let’s consider a simple weather monitoring system where we have a ‘WeatherStation’ as the subject, and various display devices (observers) like ‘CurrentConditionsDisplay’ and ‘StatisticsDisplay’ that want to be notified whenever the weather changes.

Explanation of Problem :

In this Problem:

  • ‘WeatherStation’ is the subject that maintains a list of observers and notifies them when the temperature changes.
  • ‘CurrentConditionsDisplay’ and ‘StatisticsDisplay’ are concrete observers that implement the Observer interface. They register themselves with the ‘WeatherStation’ and are notified whenever the temperature changes.
  • The ‘ObserverPatternExample’ class demonstrates how to use the Observer Pattern by creating a ‘WeatherStation’ and two display devices, registering the devices as observers, and simulating changes in temperature.

So this problem shows the flexibility of the Observer Pattern, allowing for a loosely coupled relationship between the subject and its observers.

Step Wise Implementation of above Problem:

Subject (Observable):

This is the object that maintains a list of observers and notifies us of any changes. In our case, it’s the ‘WeatherStation’ class.

Java




// Subject (Observable)
class WeatherStation {
    private List<Observer> observers = new ArrayList<>();
    private float temperature;
 
    public void addObserver(Observer observer) {
        observers.add(observer);
    }
 
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }
 
    public void setTemperature(float temperature) {
        this.temperature = temperature;
        notifyObservers();
    }
 
    private void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temperature);
        }
    }
}


Observer:

This is the observer class which is implemented by concrete observer class. ‘ConcreteObserver’ is an implementation of the ‘Observer’ interface.

The ‘update’ method is called whenever the observed object’s state changes.

Java




// Observer
interface Observer {
    void update(float temperature);
}


Concrete Observer:

These are the classes that implement the Observer interface. In our case, ‘CurrentConditionsDisplay’ and ‘StatisticsDisplay’.

Java




// Concrete Observer
class CurrentConditionsDisplay implements Observer {
    private float temperature;
 
    @Override
    public void update(float temperature) {
        this.temperature = temperature;
        display();
    }
 
    private void display() {
        System.out.println("Current Conditions Display: Temperature = " + temperature);
    }
}
 
// Concrete Observer
class StatisticsDisplay implements Observer {
    private float temperature;
 
    @Override
    public void update(float temperature) {
        this.temperature = temperature;
        display();
    }
 
    private void display() {
        System.out.println("Statistics Display: Temperature = " + temperature);
    }
}


Main Program :

This main class is used to give inputs to the problem and called the observer methods declared above, in out case the main class is ‘ObserverPatternExample’.

Java




// Main class
public class ObserverPatternExample {
    public static void main(String[] args) {
        WeatherStation weatherStation = new WeatherStation();
 
        CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay();
        StatisticsDisplay statisticsDisplay = new StatisticsDisplay();
 
        weatherStation.addObserver(currentConditionsDisplay);
        weatherStation.addObserver(statisticsDisplay);
 
        // Simulate a change in temperature
        weatherStation.setTemperature(25.5f);
        // Output:
        // Current Conditions Display: Temperature = 25.5
        // Statistics Display: Temperature = 25.5
 
        // Simulate another change in temperature
        weatherStation.setTemperature(30.0f);
        // Output:
        // Current Conditions Display: Temperature = 30.0
        // Statistics Display: Temperature = 30.0
 
        // Remove an observer
        weatherStation.removeObserver(currentConditionsDisplay);
 
        // Simulate another change in temperature
        weatherStation.setTemperature(28.0f);
        // Output:
        // Statistics Display: Temperature = 28.0
    }
}


Overall Code Implementation of above Problem

Java




import java.util.ArrayList;
import java.util.List;
 
// Subject (Observable)
class WeatherStation {
    private List<Observer> observers = new ArrayList<>();
    private float temperature;
 
    public void addObserver(Observer observer) {
        observers.add(observer);
    }
 
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }
 
    public void setTemperature(float temperature) {
        this.temperature = temperature;
        notifyObservers();
    }
 
    private void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temperature);
        }
    }
}
 
// Observer
interface Observer {
    void update(float temperature);
}
 
// Concrete Observer
class CurrentConditionsDisplay implements Observer {
    private float temperature;
 
    @Override
    public void update(float temperature) {
        this.temperature = temperature;
        display();
    }
 
    private void display() {
        System.out.println("Current Conditions Display: Temperature = " + temperature);
    }
}
 
// Concrete Observer
class StatisticsDisplay implements Observer {
    private float temperature;
 
    @Override
    public void update(float temperature) {
        this.temperature = temperature;
        display();
    }
 
    private void display() {
        System.out.println("Statistics Display: Temperature = " + temperature);
    }
}
 
// Main class
public class ObserverPatternExample {
    public static void main(String[] args) {
        WeatherStation weatherStation = new WeatherStation();
 
        CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay();
        StatisticsDisplay statisticsDisplay = new StatisticsDisplay();
 
        weatherStation.addObserver(currentConditionsDisplay);
        weatherStation.addObserver(statisticsDisplay);
 
        // Simulate a change in temperature
        weatherStation.setTemperature(25.5f);
        // Output:
        // Current Conditions Display: Temperature = 25.5
        // Statistics Display: Temperature = 25.5
 
        // Simulate another change in temperature
        weatherStation.setTemperature(30.0f);
        // Output:
        // Current Conditions Display: Temperature = 30.0
        // Statistics Display: Temperature = 30.0
 
        // Remove an observer
        weatherStation.removeObserver(currentConditionsDisplay);
 
        // Simulate another change in temperature
        weatherStation.setTemperature(28.0f);
        // Output:
        // Statistics Display: Temperature = 28.0
    }
}


Output

Current Conditions Display: Temperature = 25.5
Statistics Display: Temperature = 25.5
Current Conditions Display: Temperature = 30.0
Statistics Display: Temperature = 30.0
Statistics Display: Temperat...

Diagrammatic Representation of above Problem statement:

There are four main components of the observer method pattern are:

  • Subject (Observable)
  • Observer
  • Concrete Observer
  • Main Program
2023-11-25_9-32-32

Working of observer Pattern

Use Cases of Observer Method Design Pattern

Basically, this pattern is widely used in software development for implementing distributed event handling systems. So let’s see some common use cases for the Observer Pattern:

  • GUI Systems: In graphical user interface (GUI) development, the Observer Pattern is frequently used. For example, a button click event can be observed by multiple UI components, such as listeners or observers, that need to respond to the button click.
  • Event Handling in Libraries/Frameworks: Many programming libraries and frameworks use the Observer Pattern to manage events. For instance, in Java Swing, the observer pattern is employed to handle events generated by user interactions with graphical components.
  • Distributed Systems: Observer Pattern is useful in distributed systems where different parts of the system need to stay synchronized. When one part of the system changes state, it notifies its observers, which could be located remotely. This is essential for building loosely coupled and scalable systems.
  • Model-View-Controller (MVC) Architecture: MVC is a widely used architectural pattern, and the Observer Pattern is a fundamental part of it. The model notifies its observers (views) when its state changes, and the views update accordingly. This separation of concerns makes the system more modular and easier to maintain.
  • Stock Market Applications: In financial applications, the Observer Pattern can be used to implement real-time stock market data updates. Various components (observers) interested in stock prices can subscribe to updates, and when the stock prices change, all the subscribers are notified.
  • Logging and Monitoring Systems: In logging and monitoring applications, the Observer Pattern can be used to notify different monitoring components when certain events or thresholds are reached. This allows for flexible and extensible monitoring systems.
  • Chat Applications: Chat applications can use the Observer Pattern to notify users about new messages. When a user sends a message, all other users who are part of the conversation can be notified and update their chat interfaces accordingly.
  • Custom Events in Software Systems: When a software system needs a custom event system where certain actions trigger responses in other parts of the system, the Observer Pattern can be employed to manage these custom events.

Advantage of Observer Method Design Pattern

The primary advantage of the Observer Pattern lies in its ability to establish a loosely coupled design between the subject (the object that is being observed) and its observers (the objects that are interested in its state). Here are some key advantages:

  • Loose Coupling: The Observer Pattern promotes loose coupling between the subject and its observers. The subject doesn’t need to know anything about the observers, and vice versa. This makes it easier to make changes to either the subject or the observers without affecting the other.
  • Modular Design: Because of the loose coupling, the components (subject and observers) can be developed and modified independently. This leads to a more modular and maintainable design.
  • Reusability: Since observers are independent components, they can be reused in different contexts. we can have different observers reacting to the same subject in different ways, depending on the requirements.
  • Extensibility: It’s easy to add or remove observers without modifying the subject. This makes the system more extensible, allowing for dynamic changes in the number and types of observers.
  • Broadcast Communication: The pattern enables a “broadcast” communication mechanism. When the state of the subject changes, all registered observers are automatically notified. This is particularly useful in scenarios where multiple objects need to react to changes in another object.
  • Support for Event Handling: The Observer Pattern is commonly used in event handling systems. Events are essentially changes in state, and the observer pattern provides a way to handle and respond to these events.
  • Reduction of Dependencies: By using the Observer Pattern, dependencies between objects are minimized. This reduction in dependencies can lead to a more flexible and maintainable codebase.

Disadvantage of Observer Method Design Pattern

While the Observer Pattern offers several advantages, it’s important to be aware of potential disadvantages or challenges associated with its implementation:

  • Unintended Updates: Observers are notified whenever the subject’s state changes. In some cases, this can lead to observers being updated even when the change in state is not relevant to them. This can result in unnecessary computations or actions.
  • Performance Overhead: The pattern can introduce a performance overhead, especially when there are a large number of observers. Notifying all observers about a state change might be computationally expensive, and it’s important to optimize this process if performance is a critical concern.
  • Potential for Memory Leaks: If not implemented carefully, the Observer Pattern can lead to memory leaks. This can happen if observers are not properly deregistered from the subject when they are no longer needed. Failing to remove references to observers can prevent them from being garbage collected.
  • Difficulty in Debugging: The decoupling achieved by the Observer Pattern can make it challenging to trace the flow of control during debugging. Understanding the sequence of events and the interactions between subjects and observers might require careful inspection.
  • Potential for Update Cascades: Changes in the state of a subject can trigger a cascade of updates to observers. If observers, in turn, modify the subject’s state, it can lead to a chain reaction of updates. Managing such cascades can be complex and might require additional safeguards.
  • Complexity in Understanding Flow: For developers unfamiliar with the pattern, understanding the flow of control between subjects and observers can be challenging. The asynchronous nature of the pattern, where observers react to changes that they are not explicitly aware of, can make code harder to reason about.
  • Potential for Tight Coupling in Poor Implementations: While one of the key advantages of the Observer Pattern is loose coupling, poor implementations might inadvertently introduce tight coupling. This can happen if observers have direct dependencies on the internal implementation details of the subject.


Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads