What is the Observer pattern and when would you use it?
The Observer pattern (also called Publish-Subscribe or Event Listener) defines a one-to-many dependency between objects: when the **subject** (publisher/observable) changes state, all registered **observers** (subscribers/listeners) are notified and updated automatically.
The core problem it solves: how do you avoid tight coupling between an object that produces events and the objects that react to those events? Without Observer, the subject would need to know about every interested party and call them directly.
**Structure:** - **Subject/Observable:** maintains a list of observers, provides `subscribe(observer)` and `unsubscribe(observer)` methods, calls `notify()` on all observers when state changes - **Observer interface:** defines the `update(event)` method all observers implement - **Concrete Observers:** implement specific reactions
Python example (stock price monitor):
```python from abc import ABC, abstractmethod from typing import List
class Observer(ABC): @abstractmethod def update(self, price: float): ...
class StockTicker: def __init__(self): self._observers: List[Observer] = [] self._price: float = 0.0
def subscribe(self, obs: Observer): self._observers.append(obs)
def set_price(self, price: float): self._price = price for obs in self._observers: obs.update(price)
class AlertObserver(Observer): def update(self, price: float): if price > 100: print(f'Alert: price is {price}') ```
**When to use:** - One object's change requires updating an unknown number of other objects (GUI event systems, event buses, reactive programming) - Decoupling is more important than call-graph clarity (different subsystems reacting to domain events) - Real-world examples: Django signals, `EventEmitter` in Node.js, `Observable` in RxJS, `UIControl` target-action in iOS, pytest hooks
**Pitfalls:** - **Memory leaks:** If observers hold strong references to the subject (or vice versa), neither can be garbage collected. Use `weakref` for observer lists in long-lived subjects. - **Unexpected notification order:** Observers are notified in registration order by default. Don't write code that depends on this ordering. - **Cascading updates:** An observer that modifies the subject triggers another notification cycle — can cause infinite loops or hard-to-trace bugs. - **Synchronous blocking:** In Python's standard Observer, `notify()` is synchronous. A slow observer blocks the subject. For high-throughput systems, push to a message queue instead. - **Debugging difficulty:** The implicit call graph makes stack traces hard to follow. Structured logging in observers and subjects is essential.
Distinguish from Strategy: Observer is about communication between objects; Strategy is about swappable algorithms.
Correctly defines the one-to-many notification mechanism, gives a concrete real-world example, and names subscribe/unsubscribe/notify as the core interface.
Covers structure, real examples (Django signals, EventEmitter), memory leak via strong references, cascading update risk, synchronous blocking limitation, and distinguishes from Strategy/Pub-Sub variants.
Reading the answer is step one. Explaining it unprompted — under interview pressure — is what actually matters. Get AI-graded feedback on your answer with follow-up probes on your weak points.
Get Graded — Free Assessment