← Back to Home
Observer Pattern
Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
What is it?
Observer Pattern **eliminates tight coupling** and **prevents missed notifications** by automatically distributing events to all subscribers.
Demo: The Notification Distribution Problem
You need to notify Email, SMS, Push, and Slack services when events happen. Watch what happens when you add services and publish events:
👀 Observer Pattern
Automatic notification to ALL subscribers
Add Notification Services:
Active Subscribers (0):
No subscribers yet...
Publish Events:
Event Log:
No activity yet...
📧 Manual Notification
Hardcoded logic - misses notifications!
Add Notification Services:
Active Services (0):
No services yet...
Publish Events:
Event Log:
No activity yet...
💡 The Key Difference:
- • **Observer Pattern**: Automatically notifies ALL subscribers - never misses anyone
- • **Manual Notification**: Hardcoded logic often forgets services (notice Slack gets missed!)
- • Try adding Slack and publishing events - see how manual approach fails!
Code Example: The Real Problem
// Observer Pattern - Add once, notify everywhere automatically
class EventPublisher {
private observers: NotificationObserver[] = [];
subscribe(observer: NotificationObserver) {
this.observers.push(observer);
}
publishEvent(event: string) {
// AUTOMATIC: All observers get notified
this.observers.forEach(observer => {
observer.notify(event); // Works automatically
});
}
}
// Usage - New services automatically get ALL events:
publisher.subscribe(new EmailObserver());
publisher.subscribe(new SMSObserver());
publisher.subscribe(new SlackObserver()); // Add once
publisher.subscribe(new DiscordObserver()); // Add once
publisher.publishEvent("Order Placed"); // ALL 4 services notified automatically
// vs Manual Notification - Easy to miss services
class ManualNotificationSystem {
publishEvent(event: string) {
// MANUAL: Must remember every service type
if (this.emailService) this.emailService.notify(event);
if (this.smsService) this.smsService.notify(event);
if (this.pushService) this.pushService.notify(event);
// OOPS! Forgot Slack again!
// OOPS! Forgot Discord again!
}
}
// PROBLEM: Every event publisher must manually list all services
class OrderService {
processOrder() {
// Must manually notify each service - easy to miss one
this.emailService.notify("Order Placed");
this.smsService.notify("Order Placed");
// Forgot push and slack notifications!
}
}
class PaymentService {
processPayment() {
// Must manually notify each service - easy to miss one
this.emailService.notify("Payment Processed");
// Forgot SMS, push, and slack notifications!
}
}
// RESULT:
// Observer: Subscribe once → get ALL events automatically
// Manual: Update every event publisher → high chance of missing notificationsCommon Uses
- Event handling systems (DOM events, custom application events)
- Notification systems (email, SMS, push, Slack, Discord)
- Model-View architectures (data changes automatically update UI)
- Reactive programming (state changes trigger automatic updates)
- Pub-sub message systems (microservices, event-driven architecture)
When to Use
- When multiple objects need to stay in sync with one object
- You want to avoid tight coupling between event publishers and subscribers
- When you need to broadcast changes to an unknown number of objects
- To prevent missed notifications in complex systems
Caution
- Can cause memory leaks if subscribers aren't properly cleaned up
- Too many observers can affect performance
- Debugging can be harder due to indirect relationships
- Unexpected update sequences can cause issues if not carefully designed