← 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 notifications
Common 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