creational

Observer

Define a one-to-many dependency so dependents are notified automatically when state changes.

One object changes, and several others need to know. An order is placed, so you send an email, update stock and refresh a dashboard.

The simple approach is for the order code to call all three. But now it depends on all three. Adding a fourth means editing it again, and testing it means having all of them available.

Observer flips this around. Interested objects register themselves. The source keeps a list and notifies everyone on it, without knowing what any of them actually do.

A YouTube channel — upload a video and all subscribers get notified. Subscribers can join or leave freely.

Key Concepts

1
The subject keeps a list of observers and offers methods to add and remove them.
2
When something changes, it loops through the list and calls the same method on each one, usually update().
update()
3
Observers implement a small shared interface. The subject only knows about that interface, so it can notify anything without knowing what it is.
4
Two things to watch. Observers that never unregister keep the subject alive and leak memory. And notifications usually run one after another on the calling thread, so one slow observer holds up the rest.

When to use it

  • Event systems and UI frameworks
  • MVC architecture (model notifies views)
  • Real-time data feeds

Watch out for

  • Memory leaks if observers aren't unregistered
  • Cascading updates if observers trigger events
  • Undefined notification order
java
public class EventManager {
    private final Map<String, List<EventListener>> listeners = new HashMap<>();

    public void subscribe(String event, EventListener l) {
        listeners.computeIfAbsent(event, k -> new ArrayList<>()).add(l);
    }
    public void unsubscribe(String event, EventListener l) {
        listeners.getOrDefault(event, List.of()).remove(l);
    }
    public void notify(String event, Object data) {
        for (EventListener l : listeners.getOrDefault(event, List.of())) {
            l.update(event, data);
        }
    }
}