The Observer pattern keeps objects informed when something they care about changes. The chapter builds a weather monitoring station to motivate it.

The Weather Station problem

We’re building software for Weather-O-Rama’s weather station. A WeatherData object receives readings and exposes a measurementsChanged() method, which fires whenever new measurements come in. Our job is to use that to drive three displays: current conditions, weather stats, and a forecast — and the design should make it easy to add more displays later.

The naïve implementation

The obvious approach hard-codes each display update directly inside measurementsChanged():

measurementsChanged() {
  currentConditionsDisplay.update(temp, humidity, pressure);
  statisticsDisplay.update(temp, humidity, pressure);
  forecastDisplay.update(temp, humidity, pressure);
}

What’s wrong with it:

  • We’re coding to concrete display implementations, not an interface.
  • Every new display means editing measurementsChanged().
  • There’s no way to add or remove displays at runtime.
  • The part that changes (the set of displays) isn’t encapsulated.
  • One good sign: the displays seem to share a common update interface.

This is a textbook candidate for Observer.

The Observer pattern

The intuition is a newspaper/magazine subscription:

  1. A publisher starts publishing.
  2. Consumers subscribe; every new edition is delivered to them while they stay subscribed.
  3. They can unsubscribe at any time and delivery stops.
  4. Subscribers come and go continuously while the publisher stays in business.

Publishers + Subscribers = the Observer pattern. In pattern terms, the publisher is the Subject and the subscribers are the Observers.

A day in the life: an observer asks the subject to register it, and from then on it receives every broadcast the subject pushes out, alongside all other observers. When an observer no longer wants updates, it asks to be removed, and subsequent broadcasts skip it.

The Observer pattern defined

The Observer Pattern defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically.

One subject notifies many observers whenever its state changes.

Class structure

  • A Subject interface with methods to register, remove, and notify observers.
  • An Observer interface with an update() method.
  • A concrete subject holds a list of observers (typed to the interface) and notifies each on change.
  • Concrete observers implement Observer and register themselves with the subject.

How it achieves loose coupling

  • The subject knows only that each observer implements the Observer interface — not its concrete class or what it does.
  • Observers can be added, removed, or replaced at any time, including at runtime; the subject only depends on its list of Observer references.
  • New observer types require no change to the subject — just implement the interface.
  • Subjects and observers are independently reusable, because they aren’t tightly coupled.
  • Either side can change freely as long as both keep honouring their interfaces.

Implementing the Weather Station

WeatherData implements the Subject interface (register/remove/notify plus the observer list). Each display implements the Observer interface, and registers itself with the WeatherData subject in its constructor. When measurements change, WeatherData notifies every registered display, which then refreshes itself.

A caveat on passing data. In this version, the state variables (temp, humidity, pressure) are passed directly into update(). If the subject ever changes what it publishes — changing a type, adding, or removing data — we have to touch every observer’s update(). A more change-resistant option is to encapsulate the payload in its own object, so a change to the published data is a change in one place.

Push vs pull

  • Push (what’s implemented here): the subject pushes out the data it chooses, and observers passively consume whatever they’re given. Observers have no control over what data they receive.
  • Pull: the subject only notifies observers that its state changed, and exposes getter APIs so each observer can pull just the pieces it needs. This is more granular — an observer that needs only a couple of values fetches only those.

How Observer uses the design principles

  • Identify what varies and encapsulate it. The set of observers is what changes; the subject holds them behind the interface, so adding a new consumer of weather data requires no change to WeatherData, and vice versa — only the observers that care about new data need to change.
  • Program to an interface. The subject only ever knows its collaborators implement the Observer interface.
  • Favour composition over inheritance. Rather than inheriting observers from a parent, the subject composes a list of observers referred to only by interface, with runtime methods to add and remove them.

Source

Head First Design Patterns by Eric Freeman & Elisabeth Robson — Chapter 2: Keeping your Objects in the Know: The Observer Pattern.