Conceptly
← All Concepts
πŸ‘οΈ

Observer

BehavioralA behavioral pattern that automatically propagates state changes to subscribers

Observer is a pattern that automatically notifies other objects when an object's state changes. It separates the state-holding side (Subject) from the watching side (Observer), so the Subject does not need to know who is watching and Observers can start or stop subscribing at any time.

β–ΆArchitecture Diagram

πŸ” Structure

Dashed line animations indicate the flow direction of data or requests

Why do you need it?

It is common for a single piece of data changing to require simultaneous reactions from the UI, logs, cache, and notifications. If the data-holding object directly calls every object that needs to react, adding a new reaction means modifying the data object's code every time. The reacting side also has to know the data object's internals, so the two become tightly coupled. As features grow, this coupling cascades, and tracing which side effects occur where becomes difficult.

Why did this approach emerge?

The need became acute as GUI programming took off and a single data model had to be displayed by multiple widgets simultaneously. Smalltalk's MVC architecture addressed this head-on, requiring a structure where the Model changing automatically refreshed the Views. Observer took shape from that need, and GoF (Gang of Four) formalized it in 1994. Since then, Java event listeners, .NET events, the browser's addEventListener, and React state management libraries have all adopted variations of Observer throughout their ecosystems.

How does it work inside?

Observer has two roles. The Subject (publisher) manages a list of observers internally, registering via subscribe() and unregistering via unsubscribe(). When the Subject's state changes, its notify() method calls update() on every Observer in the list. The key property of this structure is that the Subject does not know the concrete class of any Observer. It only needs the update() interface, so adding a new Observer requires no change to the Subject. This unidirectional dependency flow allows the publishing side and consuming side to be extended independently. A point of caution: as the number of Observers grows, notification order and performance can become issues. If an Observer modifies state within its handler, cascading notifications can occur, so the notification path should be checked for cycles at design time.

What is it often confused with?

Observer and Pub/Sub both start from the goal of 'propagating changes to multiple recipients.' But in Observer, the Subject and Observer know each other directly, while Pub/Sub interposes a message broker or event channel so publishers and subscribers are completely unaware of one another. For synchronizing state between objects in the same process, Observer is simpler and more explicit. When the system is distributed or publishers and subscribers have different lifecycles, Pub/Sub achieves lower coupling. Mediator is also compared. Mediator is a pattern that centralizes complex interactions among multiple objects into a coordinator, while Observer is a pattern that unidirectionally propagates a single state change to multiple recipients. If the interactions are bidirectional, Mediator is the better fit; if unidirectional notification is the core concern, Observer is the answer.

When should you use it?

On the frontend, state management is Observer's most common application. When a global store value changes, only the components subscribed to that value re-render -- a variation of Observer. On the backend, it appears frequently in domain-event-driven architectures. When an order completes, inventory deduction, notification dispatch, and log recording each react as independent handlers. The signal for adoption is clear: when a single state change must trigger reactions in multiple places and those reacting parties are likely to grow in the future. Conversely, if there is exactly one reaction target and it will not change, a direct call is simpler. Overusing Observer makes notification paths implicit and debugging harder, so it is wise to provide logging or debug tooling alongside to trace the propagation path.

Event system -- handling user events like button clicks and form inputsState synchronization -- updating multiple views simultaneously when model data changesMessage broker -- distributing messages from a publisher to multiple subscribersReactive streams -- propagating changes in a chain through asynchronous data flows