OBSERVER / QUICK REFERENCE
The pattern,
at a glance.
Register interested listeners. Notify them through a shared contract. Unsubscribe when they leave.
- What changes?
- The listeners interested in an event.
- What stays stable?
- The publisher and the notification contract.
- Who manages the connection?
- The caller subscribes listeners and cleans up when they leave.
The four roles
- Publisher
WeatherStation - Stores subscriptions and notifies observers when a reading is published.
- Observer contract
WeatherObserver.update - The shared operation for receiving a reading.
- Concrete observer
TemperatureDisplay - Reacts to a notification in its own way, such as displaying the latest temperature.
- Caller / owner
- Registers observers and keeps cleanup functions for the end of their lifetime.
The shape in TypeScript
Actual lesson code or its Kotlin equivalent. A Reading contains an immutable temperature; this example accepts whole numbers from −20 to 50 °C.
1. One contract, a changing list
export interface WeatherObserver {
update(reading: Reading): void;
}
export class WeatherStation {
private observers = new Map<number, WeatherObserver>();
private nextId = 0;
subscribe(observer: WeatherObserver): () => void {
const id = this.nextId++;
this.observers.set(id, observer);
return () => {
this.observers.delete(id);
};
}
publish(temperature: number): void {
const reading = createReading(temperature);
// Snapshot this broadcast's recipients before delivering synchronously.
for (const observer of [...this.observers.values()]) {
observer.update(reading);
}
}
}2. Subscribe, react, clean up
export class TemperatureDisplay implements WeatherObserver {
latest: Reading | null = null;
update(reading: Reading): void {
this.latest = reading;
}
}
export function runObserverExample() {
const station = new WeatherStation();
const display = new TemperatureDisplay();
const stop = station.subscribe(display);
station.publish(18); // display receives 18 °C
stop();
station.publish(4); // display keeps 18 °C
return display.latest;
}The display receives 18 °C. After stop(), the station can publish 4 °C while that display keeps its previous value.
The interactive lesson runs this publisher. Its panel callbacks record the actual notifications.
Decide the delivery rules.
Observer describes a relationship. Timing, ordering, replay and error handling are choices your implementation must make.
This example’s delivery policy
- Delivery is synchronous and follows registration order. It does not use a queue or network.
- Each broadcast takes a snapshot of the listener list. Subscription changes during a callback affect the next broadcast.
- Subscribing does not replay an old reading. Each registration receives future readings, even when the temperature repeats.
- Registering the same object twice creates two subscriptions and two deliveries. Each cleanup removes only its own registration and is safe to repeat.
- An exception in a callback propagates and stops the remaining deliveries in that broadcast. Production code may need an explicit isolation or retry policy.
Keep the cleanup function with the object that owns the subscription. Call it when the listener leaves; otherwise the publisher can retain it and keep sending unwanted updates.
Use it for a changing audience.
A good fit
Several independent reactions to one event, UI subscriptions, or listeners with different lifetimes.
Keep it simple when you can
One fixed recipient can use a direct call. Subscriptions add lifecycle work and indirect call paths.
Common mistakes
- Forgetting cleanup. A removed panel can remain subscribed.
- Subscribing repeatedly. Mounting or rendering again can accidentally multiply notifications.
- Depending on hidden ordering. If one reaction requires another to finish, make that workflow explicit.
- Assuming guaranteed delivery. This local Observer example provides no persistence, retries or asynchronous delivery.
Compared with Strategy: Strategy selects how a job is done; Observer connects the interested listeners that react to an event.