Behavioral Pattern
Observer Pattern
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
12 min readHigh Priority
1What is Observer Pattern?
Real-World Analogy
YouTube Subscriptions
When you subscribe to a YouTube channel, you get notified whenever a new video is uploaded. You don't check manually - the channel (subject) pushes updates to all subscribers (observers).
Newsletter
When a blog publishes a new post, all newsletter subscribers receive an email. The blog doesn't know who the subscribers are - it just broadcasts to whoever signed up.
Observer (also known as Pub-Sub) is a behavioral pattern where an object (Subject) maintains a list of dependents (Observers) and notifies them automatically of any state changes. It promotes loose coupling between the subject and its observers.
Observer Pattern Structure
Subject maintains observer list and notifies on changes. Observers implement update().
2Push vs Pull Model
Push Model
// Subject sends data to observers
void notify() {
for (observer : observers) {
observer.update(this.data);
}
}- + Observers get data immediately
- + No need to query subject
- - May push unnecessary data
Pull Model
// Subject just notifies, observer pulls
void update(Subject subject) {
var data = subject.getData();
// Use only what you need
}- + Observer gets only what it needs
- + More flexible
- - Extra call to subject
3Implementation
Observer Pattern - Stock Price Alerts
import java.util.*;
// ========== Observer Interface ==========
interface StockObserver {
void update(String stockSymbol, double price);
}
// ========== Subject ==========
class Stock {
private String symbol;
private double price;
private List<StockObserver> observers = new ArrayList<>();
public Stock(String symbol, double price) {
this.symbol = symbol;
this.price = price;
}
public void attach(StockObserver observer) {
observers.add(observer);
System.out.println("Observer subscribed to " + symbol);
}
public void detach(StockObserver observer) {
observers.remove(observer);
System.out.println("Observer unsubscribed from " + symbol);
}
private void notifyObservers() {
for (StockObserver observer : observers) {
observer.update(symbol, price);
}
}
public void setPrice(double newPrice) {
System.out.println("\n" + symbol + " price changed: $" + price + " -> $" + newPrice);
this.price = newPrice;
notifyObservers(); // Notify all observers
}
public double getPrice() { return price; }
public String getSymbol() { return symbol; }
}
// ========== Concrete Observers ==========
class PriceAlertObserver implements StockObserver {
private String name;
private double threshold;
public PriceAlertObserver(String name, double threshold) {
this.name = name;
this.threshold = threshold;
}
@Override
public void update(String symbol, double price) {
if (price > threshold) {
System.out.println("[ALERT] " + name + ": " + symbol + " exceeded $" + threshold + "!");
}
}
}
class PriceLoggerObserver implements StockObserver {
@Override
public void update(String symbol, double price) {
System.out.println("[LOG] " + symbol + " is now $" + price);
}
}
class PortfolioObserver implements StockObserver {
private String name;
private int shares;
public PortfolioObserver(String name, int shares) {
this.name = name;
this.shares = shares;
}
@Override
public void update(String symbol, double price) {
double value = shares * price;
System.out.println("[PORTFOLIO] " + name + ": " + shares + " shares of " + symbol + " = $" + value);
}
}
// ========== Usage ==========
public class Main {
public static void main(String[] args) {
Stock apple = new Stock("AAPL", 150.0);
// Create observers
StockObserver alerter = new PriceAlertObserver("John", 175.0);
StockObserver logger = new PriceLoggerObserver();
StockObserver portfolio = new PortfolioObserver("Jane", 100);
// Subscribe
apple.attach(alerter);
apple.attach(logger);
apple.attach(portfolio);
// Price changes - all observers notified
apple.setPrice(160.0);
apple.setPrice(180.0); // Triggers alert
// Unsubscribe one observer
apple.detach(logger);
apple.setPrice(190.0);
}
}Output:
Observer subscribed to AAPL Observer subscribed to AAPL Observer subscribed to AAPL AAPL price changed: $150.0 -> $160.0 [LOG] AAPL is now $160.0 [PORTFOLIO] Jane: 100 shares of AAPL = $16000.0 AAPL price changed: $160.0 -> $180.0 [ALERT] John: AAPL exceeded $175.0! [LOG] AAPL is now $180.0 [PORTFOLIO] Jane: 100 shares of AAPL = $18000.0 Observer unsubscribed from AAPL AAPL price changed: $180.0 -> $190.0 [ALERT] John: AAPL exceeded $175.0! [PORTFOLIO] Jane: 100 shares of AAPL = $19000.0
4Real-World Applications
Event Listeners
button.addEventListener('click', handler)
DOM events in JavaScript. Elements (subjects) notify handlers (observers) when events occur.
MVC Pattern
Model-View separation
Model notifies Views when data changes. Multiple views can observe the same model.
Message Queues
Kafka, RabbitMQ topics
Publishers send to topics, subscribers receive. Many-to-many observer pattern.
Reactive Programming
RxJS, React useState
Observables notify subscribers of new values. Foundation of reactive frameworks.
5Observer vs Pub-Sub
| Aspect | Observer | Pub-Sub |
|---|---|---|
| Coupling | Subject knows observers | Decoupled via broker |
| Communication | Direct | Through message broker |
| Synchronous | Usually yes | Usually async |
| Example | Event listeners | Kafka, Redis Pub/Sub |
6Interview Follow-up Questions
Interview Follow-up Questions
Common follow-up questions interviewers ask
7Key Takeaways
1Observer = one-to-many dependency with automatic notification.
2Subject maintains observer list and calls update() on changes.
3Push sends data, Pull just notifies.
4Watch for: memory leaks, cascade updates, update order.
5Used in: events, MVC, reactive programming, message queues.
6Similar to Pub-Sub but with direct coupling.