2026-04-23
Imagine you're building an e-commerce system. When an order is placed, you need to: send a confirmation email, update inventory, notify the warehouse, record analytics, and trigger a loyalty points calculation. The naive approach is stuffing all of this into your placeOrder() method. Six months later, that method is 200 lines long, and adding a new post-order action means modifying core checkout logic. This is where the Observer pattern saves you.
The Observer pattern defines a one-to-many relationship: one subject (the event source) notifies multiple observers (the listeners) without knowing what they do. The subject's only job is to say "something happened." Each observer decides independently how to react.
Here's what clean implementation looks like:
subscribe() and notify() methods.handleEvent(event)).notify() when state changes, iterating through observers and invoking their handler.Back to our e-commerce example: OrderService.placeOrder() emits an OrderPlaced event. Separately registered listeners — EmailNotifier, InventoryUpdater, AnalyticsRecorder — each handle it independently. Adding a new action means registering a new observer. Zero changes to placeOrder().
When to use it vs. when to avoid it:
Rule of thumb: If three or more independent modules react to the same event, introduce the Observer pattern. Fewer than three, direct calls are simpler and easier to trace.
Common pitfalls to watch for:
unsubscribe() mechanism.placeOrder() to see everything that happens. Mitigate this with clear logging at subscription time ("AnalyticsRecorder subscribed to OrderPlaced") and in each handler.Most modern frameworks have this built in — DOM event listeners, Node.js EventEmitter, Spring's ApplicationEventPublisher, Django signals. You're likely already using the Observer pattern; now you know the principles behind it and when to reach for it deliberately.
