Behavioral 2 — Observer
In one line
One subject notifies many listeners when its state changes — the publish/subscribe idea in-process.
Key ideas
- 01
Solves: notifications fan-out (order placed → email, SMS, analytics, inventory).
- 02
Subject keeps List<Observer> and notifies on change; observers subscribe/unsubscribe freely.
- 03
Decoupling direction: subject doesn't know what observers do with the event.
- 04
Beware: synchronous observers can slow the subject — queue them or use an event bus.
- 05
Real-life example: a YouTube channel. You subscribe once, and every new video notifies you. The channel doesn't know or care what you do with the notification.
- 06
Thread safety: if listeners can subscribe while events are firing, use CopyOnWriteArrayList so the loop never throws ConcurrentModificationException.
- 07
Out-of-process version: the same idea across services is pub/sub with Kafka or SNS (Phase 10).
Java / Spring map
- →
Spring @EventListener / ApplicationEventPublisher; PropertyChangeSupport; RxJava/Reactor onNext.
Code & diagrams
Order events fan out to three listeners.
public interface OrderListener { void onOrder(Order o); }
public class OrderService {
// CopyOnWriteArrayList: safe if someone subscribes while we are notifying
private final List<OrderListener> listeners = new CopyOnWriteArrayList<>();
public void subscribe(OrderListener l) { listeners.add(l); }
public void unsubscribe(OrderListener l){ listeners.remove(l); }
public void place(Order o) {
persist(o);
for (OrderListener l : listeners) {
try { l.onOrder(o); } // fan-out
catch (RuntimeException e) { log.warn("listener failed", e); } // one bad listener can't break the rest
}
}
}
class EmailListener implements OrderListener {
public void onOrder(Order o) { System.out.println("email: " + o.id()); }
}
class AnalyticsListener implements OrderListener {
public void onOrder(Order o) { System.out.println("track: " + o.id()); }
}
class InventoryListener implements OrderListener {
public void onOrder(Order o) { System.out.println("deduct: " + o.sku()); }
}
// Spring equivalent:
// @EventListener public void on(OrderPlacedEvent e) { ... }Explain without notes
What happens to latency on the subject as observers grow — and the fix?
Practice
Convert to Spring @EventListener with three @Component listeners.
Trade-offs
- ↔
Sync fan-out adds latency to the subject; exceptions in one listener can break the whole flow.
Completion checklist
I can implement Observer safely (isolated failures, thread-safe list) and say when to move it to a message queue.