Design Patterns Observer
The Observer pattern lets one object notify many other objects when something changes. Think of it like a newspaper subscription: the newspaper (publisher) prints new editions, and every subscriber gets a copy automatically. You do not call each subscriber manually — they signed up, so they receive updates.
What Problem Does It Solve?
Imagine a weather app. The temperature sensor reads a new value. Now three things need to update: the display screen, the alarm system, and the data logger. Without Observer, you write code like this inside the sensor:
sensor.update() {
display.refresh(temp);
alarm.check(temp);
logger.record(temp);
}
Every time you add a new component, you open the sensor code and modify it. This breaks a core rule: a class should not depend on everything it notifies. The Observer pattern removes that tight connection.
Core Roles in Observer
Subject (Publisher)
The Subject holds the data. It keeps a list of observers and calls them when the data changes. It does not know what the observers do — it just calls notify().
Observer (Subscriber)
Each Observer registers with the Subject. When the Subject changes, each Observer receives the new data and reacts in its own way.
A Diagram in Plain Text
+------------------+ +--------------------+ | WeatherStation | | <<Observer>> | | (Subject) | | update(temp) | | | +--------------------+ | observers[] | /\ | attach(o) | ________|________ | detach(o) | | | | | notify() |---> [Display][Alarm][Logger] +------------------+
The WeatherStation calls notify(). Each item in the observers[] list runs its own update() method.
Code Example in Java
Step 1 — Define the Observer Interface
interface Observer {
void update(float temperature);
}
Step 2 — Define the Subject Interface
interface Subject {
void attach(Observer o);
void detach(Observer o);
void notifyObservers();
}
Step 3 — Build the WeatherStation
class WeatherStation implements Subject {
private List<Observer> observers = new ArrayList<>();
private float temperature;
public void attach(Observer o) {
observers.add(o);
}
public void detach(Observer o) {
observers.remove(o);
}
public void setTemperature(float temp) {
this.temperature = temp;
notifyObservers();
}
public void notifyObservers() {
for (Observer o : observers) {
o.update(temperature);
}
}
}
Step 4 — Build the Observers
class DisplayScreen implements Observer {
public void update(float temperature) {
System.out.println("Display: Temperature is " + temperature);
}
}
class AlarmSystem implements Observer {
public void update(float temperature) {
if (temperature > 40) {
System.out.println("ALARM: Overheating!");
}
}
}
Step 5 — Wire It Together
WeatherStation station = new WeatherStation(); station.attach(new DisplayScreen()); station.attach(new AlarmSystem()); station.setTemperature(35); // Display updates, no alarm station.setTemperature(45); // Display updates, alarm fires
Real-World Uses
- Event listeners in JavaScript:
button.addEventListener("click", handler)— the button is the subject, the handler is the observer. - React state / Redux: Components subscribe to a store. When state changes, every subscribed component re-renders.
- Stock price feeds: One price feed notifies multiple trading bots, dashboards, and alert systems.
- Email notifications: A new comment on a post triggers emails to all followers of that post.
Push vs Pull Variants
Push Model
The Subject sends the data directly to each observer inside the notify() call. Simple, but the observer receives everything whether it needs it or not.
Pull Model
The Subject only tells observers "something changed." Each observer then calls back to the Subject and asks for the specific data it needs. This gives observers control over what they fetch.
// Pull model: observer receives reference to subject
void update(Subject source) {
float temp = ((WeatherStation) source).getTemperature();
}
Common Mistakes to Avoid
Memory Leaks from Forgotten Detach
If an observer is destroyed but never removed from the Subject's list, the Subject holds a dead reference. Always call detach() when an observer is done.
Notification Loops
If an observer changes the Subject during its own update(), that change triggers another round of notifications. Set a flag to guard against re-entrant calls.
Update Order Dependence
Observers should not rely on being notified in a specific order. The Subject's list order may change. Design each observer to work independently.
Observer vs Event Bus
In the classic Observer pattern, observers register directly with the Subject. In an Event Bus (also called Pub/Sub), a central broker sits between publishers and subscribers. Neither side knows the other exists. Event Bus scales better for large systems; direct Observer is simpler for small, tightly related objects.
Classic Observer: Subject --directly calls--> Observer Event Bus: Publisher --posts to--> [Bus] --delivers to--> Subscriber
Benefits and Trade-offs
Benefits
- Add or remove observers at runtime without touching the Subject.
- Subject and Observer are loosely coupled — each can change independently.
- Supports broadcast communication to any number of observers.
Trade-offs
- Many observers can slow down notification if each does expensive work.
- Debugging gets harder when a change in one place causes reactions in many places.
- Order of observer execution is not guaranteed unless you enforce it explicitly.
Quick Summary
Observer defines a one-to-many relationship between objects. One Subject changes state; all attached Observers hear about it and react. Use it when multiple parts of a system need to stay in sync with a shared data source, without creating tight dependencies between them.
