Behavioral PatternsObserver PatternHard⏱️ ~4 min

Observer Pattern: Interview Questions and Variations

Common Interview Questions:
Question 1: "Design a stock trading system where multiple displays show real-time prices. How do you handle thousands of observers efficiently?"

Answer: Use a tiered notification strategy. First, group observers by interest (e.g., observers interested in AAPL vs GOOGL). Second, implement a notification manager that filters events so only relevant observers are notified. Third, for high-frequency updates, batch notifications using a time window (e.g., notify at most every 100ms). Fourth, consider async notifications using a thread pool to prevent slow observers from blocking others, but note this introduces complexity around notification order and state consistency.
Question 2: "Should observers be notified synchronously or asynchronously?"

Answer: Synchronous (default) means observers are notified in the same thread, making debugging easier and ensuring immediate consistency. Use this when observer operations are fast and order matters. Asynchronous means observers are notified via separate threads or event queue, preventing slow observers from blocking subject operations. Use this for IO-bound observers (sending emails, logging to external systems), but be aware that subject state may change before observer reads it, requiring snapshot passing or state versioning.
Design Variations:

Pull Model: Subject notifies observers with minimal or no data. Observers query subject for details they need. Advantage: Observers get only the data they care about. Disadvantage: Multiple queries can be inefficient, and subject state might change between notification and query.

Push Model: Subject sends all relevant data with notification. Advantage: More efficient, observers receive consistent snapshot. Disadvantage: Subject must know what data observers need, reducing flexibility. Sends unnecessary data to observers that do not need it all.

Hybrid Model: Subject sends essential data but allows observers to pull additional details. Example: notify with event type and entity ID, let observers load full entity if needed. This balances efficiency and flexibility.

Interview Tip: For machine coding rounds, start with synchronous pull model for simplicity. Mention async and push as optimizations you would add if performance becomes an issue. This shows pragmatism and understanding of trade-offs without overengineering.
Machine Coding Considerations:

First, decide on observer registration lifetime. Should observers auto-detach when garbage collected, or require explicit cleanup? Explicit is safer and clearer for interviews.

Second, handle observer exceptions gracefully. Wrap each observer notification in try-catch, log the error, and continue notifying other observers. Do not let one faulty observer break the notification chain.

Third, consider notification during iteration. If an observer detaches itself or adds new observers during notification, you will modify the collection while iterating. Copy the observer list before iterating: for observer in observers.copy().

Fourth, define clear observer interface methods. Instead of generic update(), use specific methods like onPriceChanged(symbol, newPrice). This makes the contract explicit and type-safe.

Coding Template Structure:

class Subject:
  observers = []
  attach(observer): observers.append(observer)
  detach(observer): observers.remove(observer)
  notifyObservers(event):
    for obs in observers.copy():
      try: obs.update(event)
      catch Exception: log error

interface Observer:
  update(event): void
Advanced Scenarios:

Conditional Updates: Not all observers need every notification. Add an interest filter: observers register with predicates (e.g., "notify only if price change exceeds 5%"). Subject evaluates predicates before notifying each observer.

Priority Observers: Some observers must be notified before others (e.g., billing before logging). Maintain observers in a priority queue or sorted list. Sort by priority before iteration in notifyObservers().

Transaction Boundaries: In systems with transactions, defer notifications until transaction commits. Accumulate events during transaction, notify observers only on successful commit. On rollback, discard events. This ensures observers never see invalid intermediate states.

Interview Tip: When asked to extend Observer for new requirements, always maintain backward compatibility. Add new optional methods with default implementations rather than changing existing interfaces, demonstrating understanding of the Open/Closed Principle in practice.
💡 Key Takeaways
Pull vs Push vs Hybrid models have different trade-offs
Handle observer exceptions to prevent cascading failures
Copy observer list before iteration to handle modifications during notification
Synchronous for simplicity, async for slow observers
Support conditional updates and priorities for complex systems
📌 Examples
1Stock ticker with filtered notifications by symbol
2Transaction-aware notifications that defer until commit
3Priority-based notification for critical observers
← Back to Observer Pattern Overview