Observer Design Pattern in Java

Observer Design Pattern in Java with Examples

In this article, I am going to discuss the Observer Design Pattern in Java with Examples. Please read our previous article where we discussed the Mediator Design Pattern in Java with Examples. The Observer Design Pattern falls under the category of Behavioral Design Pattern. In this article, we will explore the fundamental principles, advantages, and potential disadvantages of the Observer design pattern, emphasizing its significance in facilitating communication and synchronization between objects.

What is Observer Design Pattern?

According to GOF, Observer design Pattern states that Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

In software development, there are often scenarios where objects need to be notified of changes in the state of other objects. The Observer design pattern provides a solution by establishing a one-to-many dependency between objects, ensuring that changes in one object are automatically propagated to other interested objects. By decoupling the sender and receiver, the pattern promotes loose coupling and simplifies the design of event-driven systems.

The Observer design pattern is a behavioral pattern that defines a dependency relationship between objects, where one object, known as the subject or the observable, maintains a list of dependents, known as observers. When the state of the subject changes, it notifies all registered observers, allowing them to update or react accordingly. The pattern consists of two primary components: the subject and the observer. The subject defines the interface for managing observers and broadcasting state changes, while the observer defines the interface for receiving notifications. Multiple observers can be registered with a single subject, establishing a dynamic relationship that allows for flexible and efficient communication between objects.

Example to Understand Observer Design Pattern:

Let us understand the Observer Design Pattern with one Real-Time Example. Please have a look at the following diagram. Here, we are taking the example of the Amazon ECommerce Application.

Example to Understand Observer Design Pattern

As you can see in the above image, three users come to the Amazon site for buying a Mobile Phone. Unfortunately, at that time the Mobile phone is out of stock i.e. the mobile is in the Out Of Stock state. But the above three users want to buy that particular mobile phone. On the Amazon website site, there is an option called Notify Me when the product is not available in stock. What the above three users do is, simply click on the Notify Me button, so that when the product is available, the Amazon site will send a notification to them.

After a few days, the Product is available, and so the status of the Product is changed from Out of Stock to Available. So, what Amazon will do is send notifications to all the users who are registered with that particular product to get product available notifications. As we already discussed the Observer Design Pattern has two main components i.e. the Subject and the Observer. In our examples, the Mobile is the Subject and three users (i.e. User1, User2, and User3) are the Observers. For a better understanding please have a look at the following image.

Example to Understand Observer Design Pattern

As per the Observer Design Pattern, the Observers need to be registered with the Subject. In our case, the three users are registered to the notification option of the Subject. When the state changes i.e. Out of Stock to Available the Subject will send a notification to all the subscribers. 

Implementing Observer Design Pattern in Java:

A real-life scenario where the Observer pattern can be used is in a weather monitoring system. Imagine a weather station that collects data from various sensors such as temperature, humidity, wind speed, and precipitation. The Observer pattern can be employed to notify different components of the system whenever there is a change in the weather conditions. The weather station maintains a list of registered observers and sends notifications to them whenever there is an update in the weather data.

Whenever a change occurs, such as a significant drop in temperature or a sudden increase in wind speed, the weather station notifies all registered observers, which then update their respective displays or trigger specific actions. For example, the display panel may show updated weather information, the mobile application may send a notification to users, and the alarm system may activate in case of severe weather conditions.

The Observer pattern allows for loose coupling between the subject and the observers, as the subject doesn’t need to know the specific details of each observer. It also supports adding or removing observers dynamically, enabling scalability and flexibility in the weather monitoring system. The UML Diagram of this example is given below using Observer Design Pattern.

Implementing Observer Design Pattern in Java

Step 1: Create a new directory to store all the class files of this project.

Step 2: Open VS Code and create a new project, called observer.

Step 3: In the project, create a new file called Observer.java. Add the following code to the file:

public abstract class Observer
{
    protected Subject s;
    public abstract void update();
}

This is the abstract class from which other concrete classes will extend.

Step 4: In the project, create a new file called Subject.java. Add the following code to the file:

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

public class Subject
{
    private List<Observer> observers = new ArrayList<Observer>();
    private int state;

    public int getState()           {return state;}
    public void attach(Observer o)  {observers.add(o);}

    public void setState(int state)
    {
        this.state = state;
        notifyAllObservers();
    }
    
    private void notifyAllObservers()
    {
        for (Observer o : observers)
            o.update();
    }
}

Step 5: In the project, create three new files called BinaryObserver.java, OctalObserver.java, and HexObserver.java. All three of these files extend from the Observer abstract class. Add the following code to the files:

BinaryObserver.java
public class BinaryObserver extends Observer
 {
    public BinaryObserver(Subject s)
    {
        this.s = s;
        this.s.attach(this);
    }

    @Override
    public void update()
    {System.out.println(Integer.toBinaryString(s.getState()));}
}
HexObserver.java
public class HexObserver extends Observer
 {
    public HexObserver(Subject s)
    {
        this.s = s;
        this.s.attach(this);
    }

    @Override
    public void update()
    {System.out.println(Integer.toHexString(s.getState()));}
}
OctalObserver.java
public class OctalObserver extends Observer
{
    public OctalObserver(Subject s)
    {
        this.s = s;
        this.s.attach(this);
    }

    @Override
    public void update()
    {System.out.println(Integer.toOctalString(s.getState()));}
}

Step 6: In the project, create a new file called ObserverPatternDemo.java. This class will contain the main() function. Add the following code to ObserverPatternDemo.java:

public class ObserverPatternDemo
{
    public static void main(String[] args)
    {
        Subject s = new Subject();
        
        new BinaryObserver(s);
        new OctalObserver(s);
        new HexObserver(s);

        System.out.println("First state change!");
        s.setState(10);
        System.out.println("Second state change!");
        s.setState(20);
    }    
}

This main() function creates a subject. It then creates three observers, one of each concrete class created in step 5. It then changes the state of the subject. The observers have to reflect on this properly.

Step 7: Compile and execute the application. Ensure compilation is successful. Verify that the program works as expected.

Observer Design Pattern in Java with Examples

Congratulations! You now know how to implement observer patterns!

UML Diagram of Observer Design Pattern:

Now, let us see the Observer Design Pattern UML Diagram Components with our Example so that you can easily understand the UML Diagram.

UML Diagram of Observer Design Pattern

The classes can be described as follows:

  1. Observer: This is the interface that will define the basic methods that will be implemented by the concrete observer class.
  2. ConcreteObserver: This class implements the Observer interface. It implements the functions defined in the interface.
  3. Handler: This object is another object that will be used by the main() function. The responsibility of this class is to handle the objects of type Observer.
  4. DriverClass: This class contains the main() function and is responsible for the simulation of the program.
Advantages of Observer Design Pattern in Java

The advantages of using the Observer Design Pattern in Java are as follows:

  1. Loose Coupling and Decoupled Communication: The Observer pattern promotes loose coupling between objects, as the subject and observers are decoupled from each other. Observers are only aware of the subject’s interface and not the specific implementation, enabling objects to interact in a flexible and modular manner. This loose coupling enhances code maintainability, as changes to one object do not necessitate modifications to other objects.
  2. Event-Driven Architecture: The Observer pattern facilitates the design of event-driven systems by providing a standardized mechanism for event propagation. Objects can subscribe to events of interest and receive notifications when those events occur. This architecture enables a reactive and responsive system, where objects can react to changes in real time and trigger appropriate actions or updates.
  3. Scalability and Extensibility: The Observer pattern supports the dynamic addition and removal of observers, allowing for scalability and extensibility. New observers can be easily added to the subject without modifying its implementation. This flexibility enables the system to accommodate varying numbers of observers and facilitates the integration of new functionalities or modules without impacting existing components.
  4. Loose Dependency on Concrete Classes: The Observer pattern relies on interfaces, allowing observers to be loosely dependent on the concrete classes of subjects. Observers can subscribe to interfaces rather than specific implementations, enhancing code flexibility and promoting adherence to the Dependency Inversion Principle. This abstraction enables objects to be easily substituted or extended, facilitating code reuse and modularity.
  5. Maintainability and Testability: The Observer pattern improves code maintainability by separating concerns and promoting single responsibility. Observers are responsible for handling specific events or changes, ensuring that each object has a clear and focused role. This separation simplifies unit testing, as observers can be tested in isolation, verifying their behavior without the need for the entire system.
Disadvantages of Observer Design Pattern in Java

The disadvantages of using the Observer Design Pattern in Java are as follows:

  1. Complexity in Managing Observers: The Observer pattern introduces complexity in managing observers, especially in scenarios with a large number of observers or complex notification requirements. The subject must maintain a list of observers, handle subscriptions and unsubscriptions, and ensure that notifications are sent correctly. As the number of observers grows, the management of these interactions can become more intricate.
  2. Ordering and Timing Dependencies: In some cases, observers may have ordering or timing dependencies that need to be carefully managed. The order in which observers receive notifications may affect the correctness or behavior of the system. Ensuring the desired order and timing can be challenging, especially when observers rely on the state or actions of other observers.
  3. Performance Overhead: The Observer pattern can introduce performance overhead, especially in situations where notifications are frequent or expensive. Notifying a large number of observers or performing complex operations in each notification can impact the overall system performance. It is important to consider the performance requirements of the system and optimize the implementation if necessary.
  4. Potential for Unexpected Side Effects: The loose coupling provided by the Observer pattern can also lead to unexpected side effects if observers are not carefully designed and managed. Observers should avoid strong dependencies on each other or the subject to maintain the decoupled nature of the pattern. Failure to adhere to this guideline may result in unintended consequences or difficulties in understanding and debugging the system.

In the next article, I am going to discuss State Design Pattern in Java with Examples. Here, in this article, I try to explain Observer Design Pattern in Java with Examples. I hope you understood the need for and use of the Observer Design Pattern in Java.

Leave a Reply

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