Observer Design Pattern in Java – Complete Guide
ZeeshanAli-0704

ZeeshanAli-0704 @zeeshanali0704

About: I have expertise in developing and unit-testing web applications using JavaScript, React-Redux, Angular, Node.js, Next.js and KnockoutJS frameworks.

Location:
INDIA
Joined:
Aug 13, 2022

Observer Design Pattern in Java – Complete Guide

Publish Date: Jun 21
0 0

📚 Table of Contents

  1. What is the Observer Pattern?
  2. Key Participants
  3. Real world Analogy
  4. UML Diagram
  5. Java Implementation Example
  6. Use Cases in Real World Systems
  7. Advantages
  8. Disadvantages
  9. Synchronous vs Asynchronous Behavior
  10. Observer Pattern vs Pub Sub Pattern
  11. Best Practices
  12. Common Pitfalls
  13. Alternatives
  14. Summary

📡 Observer Design Pattern in Java – Complete Guide

🔍 What is the Observer Pattern?

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

It promotes loose coupling between the Subject and its Observers, allowing changes to one without tightly binding it to the others.


🧩 Key Participants

Component Role
Subject Maintains a list of observers and notifies them of any state changes.
Observer Defines an interface to update itself when notified by the Subject.
ConcreteSubject The actual subject whose state is of interest.
ConcreteObserver Reacts to updates from the subject.

🎯 Real World Analogy

Think of a YouTube channel (Subject) and its subscribers (Observers).

  • When the YouTube channel uploads a new video, all subscribers get notified.
  • The channel doesn’t care who the subscribers are—it just notifies all of them.
  • Subscribers can unsubscribe anytime, and the channel will stop notifying them.

📈 UML Diagram (Text Format)

        +---------------+
        |   Subject     |<---------------------+
        +---------------+                      |
        | +attach()     |                      |
        | +detach()     |                      |
        | +notify()     |                      |
        +---------------+                      |
                |                              |
                |                              |
        +---------------+              +---------------+
        |ConcreteSubject|              |   Observer     |
        +---------------+              +---------------+
        | -state        |              | +update()      |
        | +getState()   |              +---------------+
        | +setState()   |
        +---------------+
                |
                |
        +--------------------+
        | ConcreteObserver   |
        +--------------------+
        | -observerState     |
        | +update()          |
        +--------------------+
Enter fullscreen mode Exit fullscreen mode

💻 Java Implementation Example

Subject Interface

public interface Subject {
    void attach(Observer o);
    void detach(Observer o);
    void notifyObservers();
}
Enter fullscreen mode Exit fullscreen mode

Observer Interface

public interface Observer {
    void update(String message);
}
Enter fullscreen mode Exit fullscreen mode

ConcreteSubject

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

public class NewsAgency implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String news;

    public void setNews(String news) {
        this.news = news;
        notifyObservers();
    }

    public String getNews() {
        return news;
    }

    @Override
    public void attach(Observer o) {
        observers.add(o);
    }

    @Override
    public void detach(Observer o) {
        observers.remove(o);
    }

    @Override
    public void notifyObservers() {
        for (Observer o : observers) {
            o.update(news);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

ConcreteObserver

public class NewsChannel implements Observer {
    private String channelName;

    public NewsChannel(String name) {
        this.channelName = name;
    }

    @Override
    public void update(String news) {
        System.out.println(channelName + " received news: " + news);
    }
}
Enter fullscreen mode Exit fullscreen mode

✅ Test the Pattern

public class ObserverPatternDemo {
    public static void main(String[] args) {
        NewsAgency agency = new NewsAgency();

        Observer channel1 = new NewsChannel("CNN");
        Observer channel2 = new NewsChannel("BBC");

        agency.attach(channel1);
        agency.attach(channel2);

        agency.setNews("Breaking News: Observer Pattern Simplified!");

        // Detach one observer
        agency.detach(channel2);

        agency.setNews("Another update: Java 21 Released!");
    }
}
Enter fullscreen mode Exit fullscreen mode

🛠️ Use Cases in Real World Systems

  • GUI frameworks: Buttons notify listeners when clicked.
  • Event handling systems: Java’s AWT and Swing.
  • Messaging apps: Update users when a new message arrives.
  • Stock market systems: Notify brokers about stock price changes.
  • Realtime dashboards: Reflecting live sensor or data stream updates.

✅ Advantages

  • Loose coupling between Subject and Observer.
  • Easy to add/remove observers at runtime.
  • Promotes separation of concerns.
  • Supports broadcast communication.

❌ Disadvantages

  • Can lead to memory leaks if observers are not deregistered properly.
  • Unexpected updates can lead to bugs if not carefully handled.
  • Order of notification is not guaranteed.
  • Tight loop dependency may result if observers modify subject.

⏱️ Synchronous vs Asynchronous Behavior

Type Description Implication
Synchronous Observer updates immediately in the subject’s thread. Simple but can block if observers are slow.
Asynchronous Observer notified via separate threads or queues. More scalable, avoids blocking, but adds complexity.

Best Practice: Prefer asynchronous notification for non-trivial or time-consuming observers.


🔁 Observer Pattern vs Pub Sub Pattern

Feature Observer Pattern Publish-Subscribe Pattern
Coupling Tight (subject holds list of observers) Loose (via message broker)
Communication Direct method call Through event/message bus
Scope Local (in-process) Distributed (across systems)
Example Java Swing Listeners Kafka, RabbitMQ, EventBus

🧠 Best Practices

  • Unregister observers when they’re no longer needed.
  • Use weak references or cleanup hooks to avoid memory leaks.
  • Make notifyObservers() thread-safe if accessed concurrently.
  • Avoid business logic inside update()—delegate to services.

⚠️ Common Pitfalls

  • Memory leaks due to unremoved observers.
  • Circular updates between observers and subject.
  • Concurrency issues if subject is accessed by multiple threads.

🔄 Alternatives to Observer Pattern

Alternative When to Use
EventBus (e.g., Guava, GreenRobot) When decoupling and event-driven architecture is needed.
Reactive Programming (RxJava, Reactor) For complex data streams, transformations, backpressure handling.
Callback Interfaces For one-to-one updates.
Java’s PropertyChangeSupport In beans or POJOs needing observation.

📌 Summary (Bullet Points)

  • Observer Pattern is a behavioral design pattern for one-to-many object dependencies.
  • Subject maintains a list of observers and notifies them of state changes.
  • Ideal for event-driven architectures and UI frameworks.
  • Promotes loose coupling and scalability.
  • Supports both synchronous and asynchronous updates.
  • Use carefully to avoid memory leaks and cyclic dependencies.
  • Consider Pub-Sub, EventBus, or Reactive Streams for more scalable or distributed use cases.

📚 Explore More Design Patterns in Java


Similar Design Question : Notify me Feature on website

More Details:

Get all articles related to system design
Hastag: SystemDesignWithZeeshanAli

systemdesignwithzeeshanali

Git: https://github.com/ZeeshanAli-0704/SystemDesignWithZeeshanAli

Comments 0 total

    Add comment