Skip to content

Observer

Observer defines a one-to-many dependency between objects so that when one object — the subject — changes state, all of its dependents are notified and updated automatically. The subject keeps a list of observers and broadcasts to them without knowing their concrete types.

Suppose a newsletter publishes new articles, and several things must react: an email sender, a log, a live feed on the homepage. The crude approach is to have the publisher call each of them directly. But then the publisher must import and know every consumer, and every time you add or remove a consumer you edit the publisher. The publisher becomes a hub coupled to everything downstream.

The variation here is who is listening, and that set changes over time. Observer inverts the relationship: consumers register themselves with the subject, and the subject broadcasts to whatever list it currently holds. The publisher knows only the observer interface, so subscribers can come and go at runtime and the publisher never changes.

classDiagram
  class Subject {
    -observers: List~Observer~
    +subscribe(o)
    +unsubscribe(o)
    +notify(news)
  }
  class Observer {
    <<interface>>
    +update(news)
  }
  class EmailSubscriber {
    +update(news)
  }
  class FeedSubscriber {
    +update(news)
  }
  Subject o--> Observer
  Observer <|.. EmailSubscriber
  Observer <|.. FeedSubscriber
A Subject broadcasts updates to every registered Observer
  • Subject — holds the list of observers and exposes subscribe, unsubscribe, and a way to notify. When its state changes it broadcasts to all observers.
  • Observer — the interface every dependent implements, typically a single update method that receives the change.
  • Concrete Observer — one dependent; it reacts to the update however it likes.
  • Client — registers and removes observers and triggers state changes on the subject.

A newsletter subject that broadcasts each new headline to whatever subscribers are currently registered. Each language uses its idiomatic callback or interface mechanism.

interface Observer {
update(headline: string): void;
}
class Newsletter {
private observers = new Set<Observer>();
subscribe(o: Observer): void {
this.observers.add(o);
}
unsubscribe(o: Observer): void {
this.observers.delete(o);
}
publish(headline: string): void {
for (const o of this.observers) {
o.update(headline);
}
}
}
class EmailSubscriber implements Observer {
constructor(private readonly who: string) {}
update(headline: string): void {
console.log(`Email to ${this.who}: ${headline}`);
}
}
const news = new Newsletter();
const alice = new EmailSubscriber('alice');
news.subscribe(alice);
news.subscribe(new EmailSubscriber('bob'));
news.publish('Observer explained'); // both notified
news.unsubscribe(alice);
news.publish('Now without alice'); // only bob
  • Pro: the subject and its observers are loosely coupled — the subject knows only the observer interface.
  • Pro: observers can be added or removed at runtime, including dynamically as the program runs.
  • Pro: it is the backbone of event systems, UI bindings, and reactive data flows.
  • Con: notification order is usually unspecified, so observers must not depend on running in a fixed sequence.
  • Con: unremoved observers cause memory leaks, and a long notification chain can be hard to trace or debug.
  • Mediator also decouples senders from receivers but routes through a central hub rather than direct broadcast.
  • Command is often the payload an observer receives, turning a notification into an executable action.
What relationship does Observer define?
What does the subject know about its observers?
Why can observers be added and removed freely?
Which is a real hazard of Observer?