Description / Meta Description
Learn the Observer Design Pattern in Java with practical examples. Understand how Observer enables publish-subscribe communication, event-driven architectures, loose coupling, and real-time notifications. Discover real-world applications in Spring Events, Kafka consumers, stock market systems, and microservices.
Observer Design Pattern in Java: Building Event-Driven Systems Through Publish-Subscribe Communication
In the previous article, we explored the Strategy Pattern, which helps us dynamically select algorithms at runtime.
Strategy answers:
How do I choose behavior dynamically?
Observer answers a different question:
How do I notify multiple interested parties when something changes?
This pattern sits at the heart of:
- Event-Driven Architectures
- Kafka Consumers
- Spring Events
- Notification Systems
- Real-Time Dashboards
- Stock Market Applications
- Reactive Systems
If you’ve ever implemented an event, listener, subscriber, or callback mechanism, you’ve already used Observer Pattern.
The Problem: Tight Coupling
Imagine an e-commerce application.
A customer places an order.
Business requirements state:
Create Order
↓
Send Email
↓
Send SMS
↓
Update Analytics
↓
Update Inventory
↓
Generate Invoice
A naive implementation might look like:
public class OrderService {
public void placeOrder() {
createOrder();
emailService.send();
smsService.send();
analyticsService.update();
invoiceService.generate();
}
}
Looks fine initially.
Then new requirements arrive:
Push Notifications
WhatsApp Messages
Loyalty Points
CRM Updates
Fraud Detection
Audit Logging
Now OrderService becomes:
Massive
Tightly Coupled
Difficult To Maintain
Every new feature requires modifying existing code.
This violates:
Open/Closed Principle
What We Really Want
Instead of:
Order Service
│
├── Email
├── SMS
├── Analytics
├── Invoice
└── Audit
We want:
Order Created Event
│
▼
Subscribers
Email Listener
SMS Listener
Analytics Listener
Invoice Listener
Audit Listener
The order service shouldn’t care who listens.
It should simply publish an event.
This is Observer Pattern.
What is Observer Pattern?
Observer is a Behavioral Design Pattern that:
Defines a one-to-many dependency so that when one object changes state, all dependent objects are automatically notified.
In simple terms:
Publisher
│
▼
Many Subscribers
When something happens:
Publisher
Emits Event
All subscribers receive notification.
Real Life Example
Think about YouTube.
YouTube Channel
│
▼
Subscribers
When a new video is uploaded:
Channel
↓
Notification
↓
All Subscribers
The channel doesn’t know:
- who is watching
- where they live
- what device they use
It simply broadcasts an event.
Observer works the same way.
Observer Architecture
Subject
│
┌───────┼────────┐
│ │ │
Observer Observer Observer
The Subject publishes updates.
Observers react.
Step 1: Create Observer Interface
public interface Observer {
void update(
String event);
}
All observers implement this contract.
Step 2: Create Concrete Observers
Email Observer
public class EmailObserver
implements Observer {
@Override
public void update(
String event) {
System.out.println(
"Email Sent: " + event);
}
}
SMS Observer
public class SmsObserver
implements Observer {
@Override
public void update(
String event) {
System.out.println(
"SMS Sent: " + event);
}
}
Analytics Observer
public class AnalyticsObserver
implements Observer {
@Override
public void update(
String event) {
System.out.println(
"Analytics Updated");
}
}
Step 3: Create Subject
public class OrderPublisher {
private List<Observer> observers =
new ArrayList<>();
public void subscribe(
Observer observer) {
observers.add(observer);
}
public void notifyObservers(
String event) {
for(Observer observer
: observers) {
observer.update(event);
}
}
}
Step 4: Client Usage
OrderPublisher publisher =
new OrderPublisher();
publisher.subscribe(
new EmailObserver());
publisher.subscribe(
new SmsObserver());
publisher.subscribe(
new AnalyticsObserver());
publisher.notifyObservers(
"Order Created");
Output:
Email Sent: Order Created
SMS Sent: Order Created
Analytics Updated
One event.
Multiple reactions.
Why Observer Works
Without Observer:
Order Service
│
├── Email
├── SMS
├── Analytics
└── Invoice
High coupling.
With Observer:
Order Service
│
▼
Order Event
│
▼
Subscribers
Loose coupling.
Easy extensibility.
Enterprise Example: Payment Processing
Payment succeeds.
Event published:
Payment Successful
Subscribers:
Invoice Service
Notification Service
Audit Service
Rewards Service
Analytics Service
Each reacts independently.
No direct dependency exists between them.
Kafka as Observer Pattern
One of the most popular modern implementations.
Producer:
Order Created Event
Kafka Topic:
orders
Consumers:
Inventory Service
Billing Service
Shipping Service
Analytics Service
Architecture:
Producer
│
▼
Kafka Topic
│
┌──┼──┬───┐
Inventory
Billing
Shipping
Analytics
Classic Observer Pattern at scale.
Spring Events Example
Spring provides built-in Observer support.
Publisher:
applicationEventPublisher
.publishEvent(
new OrderCreatedEvent());
Listener:
@EventListener
public void handle(
OrderCreatedEvent event) {
}
Spring automatically manages subscriptions.
Stock Market Example
Stock price changes:
AAPL = $250
Observers:
Trading System
Mobile App
Dashboard
Alert Service
All receive updates immediately.
Observer is ideal for real-time systems.
Benefits of Observer Pattern
1. Loose Coupling
Publisher knows nothing about subscribers.
2. Easy Extensibility
Add new subscribers.
No publisher changes required.
3. Open/Closed Principle
Extend behavior without modifying existing code.
4. Event-Driven Architecture
Foundation of modern distributed systems.
5. Reusability
Observers can subscribe to multiple events.
Common Mistakes
Mistake 1: Too Many Events
Publishing events for everything can create complexity.
Use meaningful business events.
Mistake 2: Slow Subscribers
One slow observer can affect processing.
Modern systems often use:
Async Events
Kafka
Message Queues
to solve this.
Mistake 3: Circular Notifications
Observer A triggers Observer B.
Observer B triggers Observer A.
Infinite loops become possible.
Design carefully.
Observer vs Strategy
Common interview question.
Strategy
Purpose:
Choose Algorithm
Example:
Card Payment
UPI Payment
Wallet Payment
Observer
Purpose:
Notify Interested Parties
Example:
Order Created
↓
Email
SMS
Analytics
Observer vs Chain of Responsibility
Observer
One Event
Many Receivers
All subscribers receive notification.
Chain of Responsibility
One Request
Many Processors
Request travels through a pipeline.
Different intent.
When Should You Use Observer?
Use Observer when:
✔ Multiple systems react to the same event
✔ Loose coupling is important
✔ Event-driven architecture exists
✔ Real-time notifications are needed
✔ Publish-subscribe communication fits naturally
Examples:
- Notifications
- Kafka Consumers
- Spring Events
- Trading Systems
- Monitoring Platforms
- Dashboards
Avoid Observer when:
❌ Only one consumer exists
❌ Direct method calls are simpler
❌ Event volume introduces unnecessary complexity
Behavioral Patterns Covered So Far
| Pattern | Purpose |
|---|---|
| Strategy | Select algorithms dynamically |
| Observer | Publish-subscribe communication |
Behavioral Pattern Cheat Sheet
Strategy
→ Choose Behavior
Observer
→ Broadcast Events
Final Thoughts
The Observer Pattern solves one of the most common architectural challenges:
How do we allow multiple systems to react to the same event without tightly coupling them together?
By introducing publishers and subscribers, Observer enables:
- Event-driven systems
- Real-time notifications
- Scalable architectures
- Loose coupling
- Better maintainability
This is why Observer powers:
- Spring Events
- Kafka
- RabbitMQ Consumers
- Monitoring Systems
- Notification Platforms
- Reactive Applications
Whenever you see:
Something Happened
↓
Many Things Need To React
you’re looking at a perfect Observer Pattern use case.
In the next article, we’ll explore another highly practical Behavioral Pattern:
Command Design Pattern — Encapsulating Requests as Objects
You’ll learn how job schedulers, Spring Batch, Quartz, workflow engines, undo functionality, and task execution frameworks rely heavily on Command Pattern concepts.