Sometimes when one object’s state changes, several dependent objects must update. When a stock price changes, the chart, the order book, and the alert all refresh together. If the subject calls each dependent directly, it has to be edited whenever a new dependent appears, and the two become tightly coupled. Observer cuts that coupling by having the subject notify only a list of subscribers.

Shared Intent

Observer has three intents.

  • One-to-many notification — a single Subject informs many Observers of a state change.
  • Loose coupling — the Subject doesn’t know the Observers’ concrete types. It notifies only through a common interface, so it needn’t know who listens.
  • Dynamic subscription — Observers subscribe and unsubscribe at runtime. The relationship isn’t fixed.

The GoF Form

GoF defines a Subject and an Observer. The Subject holds a list of Observers and offers attach, detach, and notify. When the state changes, notify walks the list and calls each Observer’s update method.

sequenceDiagram
    participant S as Subject
    participant A as Observer A
    participant B as Observer B

    Note over S: state changes
    S->>A: update()
    S->>B: update()
interface Observer {
    void update(int price);
}

class Stock {
    private final List<Observer> observers = new ArrayList<>();
    void attach(Observer o) { observers.add(o); }
    void setPrice(int price) {
        for (Observer o : observers) o.update(price);
    }
}

Stock doesn’t know whether a subscribed Observer is a chart or an alert. setPrice merely walks the list and notifies. New subscribers enter through attach and leave through detach.

Language Implementations

Java’s built-in java.util.Observer and Observable have been deprecated since Java 9, due to thread-safety and design limitations. Today you implement it directly or use PropertyChangeListener or a framework’s event listeners.

Python expresses it simply with a list of callbacks. The Subject holds a list of functions and calls each when a change occurs.

class Stock:
    def __init__(self):
        self._observers = []
    def subscribe(self, callback):
        self._observers.append(callback)
    def set_price(self, price):
        for cb in self._observers:
            cb(price)

TypeScript’s representative is Node’s EventEmitter. You subscribe with emitter.on("price", handler) and notify with emitter.emit("price", value). Going further, RxJS’s Observable extends Observer into a stream.

Distinguishing from Pub/Sub

Observer and pub/sub look alike but differ in mediation.

  • Observer — the Subject holds the Observer list directly and notifies. The two know each other.
  • Pub/sub — publishers and subscribers communicate through an event channel or broker. They don’t know each other directly.

Notification has two forms too. Push, where notify sends the changed data along, and pull, where the Observer receives the notice and queries the Subject for the value it needs. Push is concise; pull lets the Observer take only as much as it needs.

Extending into Reactive

Observer is the root of modern reactive programming. Reactive streams like RxJS and Reactor add operator composition and backpressure control on top of Observer. In event-driven architecture, a service publishing an event and others subscribing is an extension of the same intent. The problem of one state change propagating to many places gets solved again, just at a larger scale.

Conclusion

Observer cuts coupling through a one-to-many relationship that notifies subscribers of state changes. The Subject just notifies, unaware of who listens. The decision comes down to one question.

  • Must one object’s change propagate to several objects, with a dependent list that isn’t fixed? Then Observer over direct calls.

EventEmitter, RxJS, and event-driven architecture are all variations on the same intent. What separates it from broker-mediated pub/sub is whether the parties know each other directly.

References

  • Strategy — its behavioral-pattern counterpart, on encapsulating algorithms
  • Decorator — the same GoF series
  • GoF — Design Patterns: Elements of Reusable Object-Oriented Software (1994)