Observer
Let objects subscribe to events on a publisher and get notified automatically, without the publisher knowing who they are.
The problem
A Customer desperately wants the new phone the Store is about to stock. Option one:
they visit the store every day and check. Almost every trip is wasted. Option two: the
store emails every customer about every new product. The interested customer is happy;
everyone else calls it spam.
Either the subscriber wastes effort polling, or the publisher wastes effort (and goodwill) broadcasting. In code the same tension shows up as hard-wired reactions.
Every new reaction means reopening saveFile(). The editor slowly becomes a switchboard
that knows about logging, email, status bars, and whatever next month brings.
The solution
Name the sides: the object with interesting state is the publisher; everyone tracking
it is a subscriber. The pattern adds a subscription mechanism to the publisher - just
a list of subscriber references and a couple of subscribe / unsubscribe methods. When
something notable happens, the publisher walks the list and calls the notification method
on each subscriber.
The crucial move: all subscribers implement the same interface (usually a single
update(context) method), and the publisher talks to them only through it. New subscriber
classes can appear without the publisher changing a line.
- 1At startup the application wires listeners to the events they care about. The editor is not involved.
- 2Someone saves a file. Ordinary business logic, nothing pattern-shaped yet.
- 3The editor does its actual job first. Events are a side effect, not the main act.
- 4Then it tells its EventManager that something interesting happened. It has no idea who is listening.
- 5The manager walks its list and calls update() on every subscriber of "save" - through the interface, never the concrete class.
- 6Each subscriber reacts its own way. Add an email alert tomorrow: subscribe it, done, editor untouched.
Structure
The editor example delegates list management to a helper. That is a common upgrade: the subscription machinery looks identical for every publisher, so it gets extracted, and a class that already has a superclass can still become a publisher by composition.
Code
Same example three ways: an editor notifying services about file events.
When to use it
- Changes in one object require reactions in others, and you cannot know the full set of reactors in advance - GUI events are the canonical case.
- Some objects should watch others only temporarily; the dynamic subscription list makes joining and leaving cheap.
Pitfalls
- Random notification order. Subscribers are notified in whatever order the list happens to hold them. Logic that depends on order is a latent bug.
- The lapsed listener. Forgetting to unsubscribe keeps dead objects alive (in GC languages) or calls into freed ones (elsewhere). Unsubscribe is part of the subscriber's lifecycle, not an optional courtesy.
- Notification storms. A publisher that fires on every tiny mutation can bury the system in updates; batch or debounce when state changes in bursts.
Don't confuse it with
- Mediator. Mediator's goal is eliminating mutual dependencies among components by routing communication through one hub; Observer's goal is dynamic one-way subscriptions. The confusion is earned: a Mediator is frequently implemented with an Observer inside, hub as publisher, components as subscribers.
- Chain of Responsibility. CoR passes a request along a chain until one receiver handles it; Observer hands the event to every receiver that subscribed.
- Pub/Sub middleware. Message brokers (Kafka, SNS) are the same idea grown up and moved out of process: the broker plays EventManager for entire services.
In the wild
- DOM
addEventListener. Any number of listeners can subscribe to the same button'sclickevent, the button never imports any of their code, and removing a listener is exactly the unsubscribe step this page's pitfalls section insists on. - RxJS and other reactive-stream libraries. An
Observableis a publisher and every.subscribe(...)call attaches an observer to it - the library's own name for the pattern is the pattern's name. - Redux's
store.subscribe(listener). Every registered listener is called after each state change, with no idea which other listeners exist or what they do with the notification - the UI re-render is just one particular subscriber's reaction. - Java Beans'
PropertyChangeSupport/PropertyChangeListener. The library-supplied version of the "helper the publisher delegates subscription management to" mentioned under Structure above - it predatesjava.util.Observerand is still the recommended way to do this in plain Java.
Try it yourself: a stock ticker publishes price updates for hundreds of symbols, but most subscribers only care about a handful of them. Design an Observer setup where a subscriber registers for specific symbols rather than receiving every update, and think through what changes in the publisher's subscriber list to make that efficient.
Check yourself
What is the one thing the publisher is allowed to know about its subscribers?