Observer pattern in LLD - System Design Guide
This diagram shows a Subject holding references to multiple Observers. Observers register to the Subject, and when the Subject's state changes, it notifies all registered Observers.
### Before: Without Observer Pattern class Subject: def __init__(self): self.state = None self.observer1 = None self.observer2 = None def set_state(self, state): self.state = state if self.observer1: self.observer1.update(state) if self.observer2: self.observer2.update(state) class Observer1: def update(self, state): print(f"Observer1: State updated to {state}") class Observer2: def update(self, state): print(f"Observer2: State updated to {state}") subject = Subject() subject.observer1 = Observer1() subject.observer2 = Observer2() subject.set_state('ON') ### After: With Observer Pattern class Subject: def __init__(self): self._observers = [] self._state = None def register(self, observer): self._observers.append(observer) def unregister(self, observer): self._observers.remove(observer) def notify(self): for observer in self._observers: observer.update(self._state) def set_state(self, state): self._state = state self.notify() class Observer: def update(self, state): print(f"Observer: State updated to {state}") subject = Subject() observer1 = Observer() observer2 = Observer() subject.register(observer1) subject.register(observer2) subject.set_state('ON')
Practice
What is the main purpose of the Observer pattern in system design?
Solution
Step 1: Understand the Observer pattern role
The Observer pattern is designed to let one object notify others about changes automatically.Step 2: Match purpose with options
To allow objects to automatically update when another object changes correctly describes automatic updates between objects without tight coupling.Final Answer:
To allow objects to automatically update when another object changes -> Option BQuick Check:
Observer pattern = automatic updates [OK]
- Confusing Observer with data storage
- Thinking it creates class hierarchies
- Assuming it improves function speed
Which of the following is the correct way to register an observer in the Observer pattern?
subject = Subject()
observer = ConcreteObserver()
# What code registers the observer?Solution
Step 1: Recall common Observer pattern method names
Typically, the subject has a method namedattachoraddObserverto register observers.Step 2: Identify the most standard method
WhileaddObserveris used in some languages,attachis the classic and widely accepted method name.Final Answer:
subject.attach(observer) -> Option DQuick Check:
Register observer = subject.attach(observer) [OK]
- Calling register on observer instead of subject
- Using subscribe which is not standard here
- Confusing addObserver with observer methods
Given this code snippet, what will be printed?
class Subject:
def __init__(self):
self.observers = []
self.state = 0
def attach(self, observer):
self.observers.append(observer)
def set_state(self, state):
self.state = state
for obs in self.observers:
obs.update(state)
class Observer:
def __init__(self, name):
self.name = name
def update(self, state):
print(f"{self.name} received state {state}")
subject = Subject()
obs1 = Observer('A')
obs2 = Observer('B')
subject.attach(obs1)
subject.attach(obs2)
subject.set_state(5)Solution
Step 1: Follow the attach and set_state calls
Observers A and B are attached to the subject. Whenset_state(5)is called, it updates the state and callsupdate(5)on each observer.Step 2: Understand the update method output
Each observer prints its name and the new state, so both print lines with state 5.Final Answer:
A received state 5 B received state 5 -> Option AQuick Check:
Observers print updated state 5 [OK]
- Thinking observers print old state
- Assuming no output without explicit print
- Confusing method names causing errors
Identify the bug in this Observer pattern implementation:
class Subject:
def __init__(self):
self.observers = set()
def attach(self, observer):
self.observers.add(observer)
def notify(self):
for obs in self.observers:
obs.update()
class Observer:
def update(self, state):
print(f"State updated to {state}")
subject = Subject()
obs = Observer()
subject.attach(obs)
subject.notify()Solution
Step 1: Check method signatures and calls
The Observer'supdatemethod expects astateargument, butnotifycallsupdate()without any argument.Step 2: Identify mismatch causing error
This mismatch will cause a runtime error due to missing required positional argument.Final Answer:
Observer.update requires a state argument but notify calls without it -> Option AQuick Check:
Method argument mismatch causes error [OK]
- Ignoring missing argument errors
- Thinking sets are invalid for observers
- Misunderstanding attach method purpose
You are designing a stock price alert system using the Observer pattern. Multiple clients want updates only when the stock price changes by more than 5%. How should you modify the Observer pattern to handle this efficiently?
Solution
Step 1: Understand the requirement for selective updates
Clients want updates only if price changes exceed 5%, so notifying on every change is inefficient.Step 2: Implement threshold logic in Subject
Adding a check in the Subject to compare new price with old and notify observers only if change > 5% reduces unnecessary notifications.Final Answer:
Add a threshold check in the Subject before notifying observers -> Option CQuick Check:
Efficient notify = threshold check in Subject [OK]
- Not filtering updates causing overload
- Using polling which wastes resources
- Removing Observer pattern loses decoupling benefits
Ready to prove it?
Pass the test and this pattern moves unknown
