Behavioral pattern
Observer Pattern
One subject holds state. Many observers want to react when it changes — without the subject knowing who they are. It just announces; they listen.
✗ The problem
Tight coupling to every listener
The subject hard-codes calls to each dependent. Add a listener → edit the subject.
class Stock {
setPrice(p) {
this.price = p;
// subject must KNOW every consumer:
chart.redraw(p);
alerts.check(p);
logger.record(p); // ← new? edit here again…
}
}
Every new consumer means reopening
Stock. Sound familiar? It's the
Open/Closed smell again.
✓ The pattern
↓
Invert it: subject broadcasts, observers subscribe
The subject keeps a list of subscribers and just calls update() on each.
It has no idea what they do.
class Subject {
subs = [];
subscribe(o) { this.subs.push(o); }
unsubscribe(o) {
this.subs = this.subs.filter(s => s !== o);
}
notify(data) {
this.subs.forEach(o => o.update(data));
}
}
Subject
notify()
Observer A
Observer B
Observer C
✓ See it live
Publish an event — watch it ripple
Set a new stock price. The subject notifies every subscribed observer. Toggle observers on/off — the subject never changes.
📈 Stock $100
📊
Chart
—
🔔
Alerts
—
🗒️
Logger
—
0 observers notified
Tip: click an observer to unsubscribe it, then publish again.
✓ Takeaway
Loose coupling by broadcast
- Subject depends only on an
update()contract — not on concrete observers. - Add / remove observers at runtime; the subject's code never changes.
- You already use it: DOM
addEventListener, RxJS, React state, pub/sub queues. - Careful: unsubscribe when done (memory leaks) and beware notification storms / ordering.
🎯 Principle applied: Observer buys loose coupling through Dependency Inversion (the subject depends only on the
update() contract) and Open/Closed (add or remove subscribers without editing the subject).Back to all topics →