Design Patterns interview question · Most asked
Explain the Observer pattern and give examples from real frameworks.
Summary
Observer lets a subject notify any number of subscribers when something happens, without knowing what they do. Subscribers register and unregister at runtime. Examples: DOM addEventListener, Node.js EventEmitter, RxJS, Laravel events and model observers, Django signals, Spring application events.
Longer Answer
It decouples the source of an event from its reactions: order placement doesn't import email, analytics and inventory code; they subscribe. Decide how ordering and errors are handled (one failing observer shouldn't break the subject unless it must), and always unsubscribe to avoid memory leaks.
Across processes or services, use Pub/Sub with a broker instead of in-process observers.
Code Example
class Events:
def __init__(self):
self.subscribers = []
def subscribe(self, fn):
self.subscribers.append(fn)
def publish(self, order_id):
for fn in self.subscribers:
fn(order_id)
events = Events()
events.subscribe(lambda oid: print(f"email: receipt for {oid}"))
events.subscribe(lambda oid: print(f"stock: reserve for {oid}"))
events.publish(42)
class Events {
private subscribers: ((orderId: number) => void)[] = [];
subscribe(fn: (orderId: number) => void) { this.subscribers.push(fn); }
publish(orderId: number) { for (const fn of this.subscribers) fn(orderId); }
}
const events = new Events();
events.subscribe((oid) => console.log(`email: receipt for ${oid}`));
events.subscribe((oid) => console.log(`stock: reserve for ${oid}`));
events.publish(42);
import java.util.ArrayList;
import java.util.List;
import java.util.function.IntConsumer;
public class Main {
public static void main(String[] args) {
Events events = new Events();
events.subscribe(oid -> System.out.println("email: receipt for " + oid));
events.subscribe(oid -> System.out.println("stock: reserve for " + oid));
events.publish(42);
}
}
class Events {
private final List<IntConsumer> subscribers = new ArrayList<>();
void subscribe(IntConsumer fn) { subscribers.add(fn); }
void publish(int orderId) { subscribers.forEach(fn -> fn.accept(orderId)); }
}
<?php
class Events {
private array $subscribers = [];
public function subscribe(callable $fn): void { $this->subscribers[] = $fn; }
public function publish(int $orderId): void { foreach ($this->subscribers as $fn) $fn($orderId); }
}
$events = new Events();
$events->subscribe(fn($oid) => print("email: receipt for $oid\n"));
$events->subscribe(fn($oid) => print("stock: reserve for $oid\n"));
$events->publish(42);
Key Points
- Subject notifies subscribers it doesn't know.
- Subscribe/unsubscribe at runtime.
- Handle observer errors and ordering deliberately.
- Unsubscribe to avoid leaks.
Deep dive: Design Patterns, Explained Simply: Observer
Explanation
What interviewers look for
Decoupling benefit, real framework examples, and awareness of leaks and error handling.
Follow-up questions
- How is Observer different from Pub/Sub?
- How do you avoid memory leaks with observers?
More most-asked Design Patterns questions
- What problem does the Builder pattern solve? Show an example.
- Explain the SOLID principles.
- What is a design pattern, and why are they useful?
- What is the difference between dependency inversion, dependency injection and inversion of control?
- Why is composition often preferred over inheritance?
- What is dependency injection, and what forms does it take?
- Explain the Factory Method pattern and how it differs from a simple factory.
- How do you implement a Singleton, and why is it often considered an anti-pattern?