Blog Design Pattern

Observer Design Pattern Explained: Subscribe to State Changes with Examples and Implemented in Java | Behavioral Design Patterns

The Observer Design Pattern: Keeping Objects in Sync

In software development, it’s common to have objects that need to be notified when the state of another object changes. For example, you might have a data model object that needs to notify multiple user interface components when its data is updated.

The Observer Design Pattern provides an elegant solution for this scenario, allowing objects to subscribe to and receive notifications from other objects.

How Observer Design Pattern Works

The Observer pattern involves two main components: the Subject and the Observers.

  1. Subject: The Subject is the object that holds the state that needs to be observed. It maintains a list of Observers and provides methods for Observers to subscribe and unsubscribe to notifications.
  2. Observers: The Observers are objects that are interested in the state changes of the Subject. They subscribe to the Subject and implement a specific update method that is called by the Subject when its state changes.

The following diagram illustrates the Observer Design Pattern. Here’s a simple yet effective diagram:

+---------------+
|    Subject    |
+---------------+
| -observers    |
|---------------| 
| +attach()     |
| +detach()     |
| +notify()     |
+---------------+
      |
      | notifies
      |
+---------------+
|   Observer1   |
+---------------+
| +update()     |
+---------------+
      |
      |
+---------------+
|   Observer2   |  
+---------------+
| +update()     |
+---------------+
      |
      |
      ...

In this diagram:

  • The Subject class maintains a list of Observer objects and provides methods to attach (attach()), detach (detach()), and notify (notify()) observers.
  • The Observer classes implement an update() method, which gets called by the Subject when its state changes.
  • The arrows indicate the flow of notifications from the Subject to the Observer objects.

This diagram illustrates the one-to-many relationship between the Subject and Observer objects, where the Subject can have multiple Observer objects attached to it. When the Subject‘s state changes, it notifies all attached Observer objects by calling their update() method.

You can further enhance this diagram by adding specific class names or details based on your implementation or the programming language you’re using.

An example implementation of the Observer Design Pattern in Java:

Java
// Subject interface
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// Concrete Subject
class DataModel implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String data;

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(data);
        }
    }

    public void setData(String data) {
        this.data = data;
        notifyObservers();
    }
}

// Observer interface
interface Observer {
    void update(String data);
}

// Concrete Observer
class UserInterface implements Observer {
    private String uiName;

    public UserInterface(String uiName) {
        this.uiName = uiName;
    }

    @Override
    public void update(String data) {
        System.out.println("UI " + uiName + " received data: " + data);
    }
}

// Usage example
public class ObserverExample {
    public static void main(String[] args) {
        DataModel model = new DataModel();

        UserInterface ui1 = new UserInterface("UI1");
        UserInterface ui2 = new UserInterface("UI2");

        model.registerObserver(ui1);
        model.registerObserver(ui2);

        model.setData("New data");
        model.notifyObserver();
        // Output:
        // UI UI1 received data: New data
        // UI UI2 received data: New data
    }
}


In this example:

  1. The Subject interface defines the methods that a Subject must implement: registerObserverremoveObserver, and notifyObservers.
  2. The DataModel class is a concrete implementation of the Subject interface. It maintains a list of Observer objects and provides methods to register, remove, and notify observers.
  3. The Observer interface defines the update method that must be implemented by Observer classes.
  4. The UserInterface class is a concrete implementation of the Observer interface. It simply prints a message when its update method is called.
  5. In the main method, we create a DataModel object (the Subject) and two UserInterface objects (the Observers). We register the UserInterface objects with the DataModel, and then call the setData method on the DataModel. This notifies both UserInterface objects, and they print their respective messages.

This implementation follows the Observer pattern, allowing the DataModel to notify any registered Observer objects when its data changes, without the Observer objects having to directly depend on the DataModel class.

Happy coding! 🖌️✨🌟

🚀 Boost Your Coding Skills with These Design Pattern Guides! 🔥

  1. 🏭 Unlock the Power of Abstract Factory with Our Comprehensive Guide
  2. 🌉 Bridge the Gap with Our Bridge Pattern Guide for Seamless Design
  3. 🧱 Build Robust Software with Our Builder Pattern Guide
  4. 🎨 Decorate Your Code with Elegance: The Decorator Pattern Explained
  5. 🏛️ Simplify Complex Systems with Our Facade Pattern Guide
  6. 👀 Stay Notified with Our In-Depth Observer Pattern Walkthrough
  7. 🦸 Mastering the Singleton Design Pattern in Java: A Guide for Developers
  8. 📦 Factory Method Pattern: The Ultimate Guide to Creating Objects
  9. 🧩 Composite Pattern: Mastering the Art of Hierarchical Data Structures
  10. 💻 Unveiling the Proxy Pattern: Control Access Like a Pro
  11. 🔑 Flyweight Pattern: Optimizing Memory Usage with Ease
  12. 🧪 Prototype Pattern: Cloning Made Simple and Efficient
  13. 🌳 Adapter Pattern: Bridging the Gap Between Incompatible Interfaces
  14. 🕰️ Iterator Pattern: Traversing Data Structures with Elegance
  15. 💼 Strategy Pattern: Encapsulating Algorithms for Ultimate Flexibility
Avatar

Neelabh

About Author

As Neelabh Singh, I am a Senior Software Engineer with 6.6 years of experience, specializing in Java technologies, Microservices, AWS, Algorithms, and Data Structures. I am also a technology blogger and an active participant in several online coding communities.

You may also like

Blog Design Pattern

Understanding the Builder Design Pattern in Java | Creational Design Patterns | CodeTechSummit

Overview The Builder design pattern is a creational pattern used to construct a complex object step by step. It separates
Blog Tech Toolkit

Base64 Decode

Base64 encoding is a technique used to encode binary data into ASCII characters, making it easier to transmit data over