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.
Check yourself
What is the one thing the publisher is allowed to know about its subscribers?