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- observers: List+ attach(Observer)+ notify()<<interface>>Observer+ update(data)notifiesConcreteObserverAConcreteObserverB
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

AspectObserverPub-Sub
CouplingSubject knows observersDecoupled via broker
CommunicationDirectThrough message broker
SynchronousUsually yesUsually async
ExampleEvent listenersKafka, 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.