What Problem It Solves
When one object changes, multiple dependent objects need to be notified. You don't want the subject to know about every observer. Observer decouples the subject (publisher) from observers (subscribers).
Observer vs Pub-Sub
| Aspect | Observer | Pub-Sub |
|---|---|---|
| Coupling | Subject knows observers (via interface) | Publisher and subscriber don't know each other |
| Delivery | Direct (in-process) | Via broker (Kafka, Redis, in-memory bus) |
| Failure | One slow observer blocks others | Async queue decouples |
| LLD fit | In-process notification, small scale | Cross-service, large scale |
Common Interview Traps
| Trap | Why | Fix |
|---|---|---|
| Forgetting observer removal | Memory leak (observer holds reference to subject) |
|
| Blocking in observer callback | Slow observer delays all others | Use async notification (event queue) |
| Notification order dependency | Observers assume specific order | Observers should be order-independent |
| Observing the same subject twice | Double processing | Check before adding |
Observer Variants
| Variant | How | When |
|---|---|---|
| Pull |
| Observers need different data subsets |
| Push | Subject sends full data with notification | Observers need the same data |
| Async (Event Bus) | Uses a message queue between subject and observers | Decouple in time, not just space (Kafka/Redis pub/sub) |
Where Observer Appears in LLD Problems
| Problem | Subject | Observers | Notification Trigger |
|---|---|---|---|
| Notification Service (#18) | NotificationManager | EmailHandler, SMSHandler, PushHandler | New notification created |
| Live Comments (#73) | CommentStream | WebSocketPush, CacheUpdater, AnalyticsTracker | New comment posted |
| Stock Brokerage (#29) | StockMarket | MobileApp, EmailAlert, TradingBot | Price change |
| Pub-Sub (#11) | Topic/PubSubManager | RegisteredSubscriber instances | Message published |
| Chat (#37) | ChatRoom | UserConnections | New message in room |
| Metrics (#75) | MetricCollector | DashboardUpdater, AlertEvaluator, LogWriter | Metric recorded |
Implementation
// โโโ EXAMPLE 1 โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// WHAT WE ARE IMPLEMENTING:
// An online store inventory monitor alerting waiting buyers immediately when
// an out-of-stock item is replenished.
//
// WHERE THE OBSERVER FITS IN:
// Subject is the Observable (e.g., Product). Observer is the Subscriber
// interface. Customer classes act as Concrete Observers.
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
import java.util.concurrent.CopyOnWriteArrayList;
// --- Observer interface ---
interface StockObserver {
void update(String symbol, double price);
}
// --- Subject ---
class StockMarket {
private final java.util.List<StockObserver> observers = new CopyOnWriteArrayList<>();
private final java.util.Map<String, Double> prices = new java.util.HashMap<>();
public void addObserver(StockObserver obs) { observers.add(obs); }
public void removeObserver(StockObserver obs) { observers.remove(obs); }
public void setPrice(String symbol, double price) {
prices.put(symbol, price);
notifyObservers(symbol, price);
}
private void notifyObservers(String symbol, double price) {
for (StockObserver obs : observers) {
obs.update(symbol, price);
}
}
}
// --- Concrete observers ---
class MobileApp implements StockObserver {
private final String name;
public MobileApp(String name) { this.name = name; }
public void update(String symbol, double price) {
System.out.println(" [MobileApp " + name + "] " + symbol + " now $" + price);
}
}
class EmailAlertService implements StockObserver {
public void update(String symbol, double price) {
if (price > 500) {
System.out.println(" [EMAIL ALERT] " + symbol + " crossed $500 at $" + price);
}
}
}
class TradingBot implements StockObserver {
public void update(String symbol, double price) {
if (price < 50) {
System.out.println(" [TradingBot] Buying " + symbol + " at $" + price);
}
}
}
public class Main {
public static void main(String[] args) {
StockMarket market = new StockMarket();
market.addObserver(new MobileApp("Alice"));
market.addObserver(new MobileApp("Bob"));
market.addObserver(new EmailAlertService());
market.addObserver(new TradingBot());
System.out.println("--- Price Update: AAPL ---");
market.setPrice("AAPL", 150.0);
System.out.println("\n--- Price Update: TSLA ---");
market.setPrice("TSLA", 520.0);
}
}Review
Help Us Improve
How helpful was this walkthrough?
Click a star to rate. We actively use this feedback to refine and update our system design content.
Placeholder
Discussion
Share your thoughts, ask questions, or help others.
Loading comments...