📚 Table of Contents
- What is the Observer Pattern?
- Key Participants
- Real world Analogy
- UML Diagram
- Java Implementation Example
- Use Cases in Real World Systems
- Advantages
- Disadvantages
- Synchronous vs Asynchronous Behavior
- Observer Pattern vs Pub Sub Pattern
- Best Practices
- Common Pitfalls
- Alternatives
- 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() |
+--------------------+
💻 Java Implementation Example
Subject
Interface
public interface Subject {
void attach(Observer o);
void detach(Observer o);
void notifyObservers();
}
Observer
Interface
public interface Observer {
void update(String message);
}
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);
}
}
}
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);
}
}
✅ 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!");
}
}
🛠️ 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
- 🔒 Mastering the Singleton Design Pattern in Java – A Complete Guide
- ⚠️ Why You Should Avoid Singleton Pattern in Modern Java Projects
- 🏭 Factory Design Pattern in Java – A Complete Guide
- 🧰 Abstract Factory Design Pattern in Java – Complete Guide with Examples
- 🧱 Builder Design Pattern in Java – A Complete Guide
- 🔁 Iterator Design Pattern in Java – Complete Guide
- 🔌 Adapter Design Pattern in Java – A Complete Guide
- 🔌 Strategy Design Pattern in Java – A Complete Guide
- 🔁 Decorator Design Pattern in Java – Complete Guide
Similar Design Question : Notify me Feature on website
More Details:
Get all articles related to system design
Hastag: SystemDesignWithZeeshanAli
Git: https://github.com/ZeeshanAli-0704/SystemDesignWithZeeshanAli