Practice
Solution
Step 1: Understand delegation in composition
In composition, the main object delegates responsibilities to composed behavior objects rather than handling all logic itself.Step 2: Analyze each option
The object directly executes the action code inherited from its superclass describes inheritance, not composition. The object checks flags internally and runs conditional code for each behavior implies flag-based conditional logic, which is less flexible. The object creates a new subclass instance dynamically to handle the action is not a typical or practical approach.Step 3: Confirm correct flow
The composed behaviors receive the delegated call and execute their specific logic, enabling modular and maintainable design.Final Answer:
Option A -> Option AQuick Check:
Delegation to composed objects is the hallmark of composition-based design.
- Confusing inheritance method calls with composition delegation
- Assuming flags control behavior execution internally
import threading
class Observer:
def __init__(self, name):
self.name = name
def update(self, event_type, message):
print(f"{self.name} received {event_type}: {message}")
class Subject:
def __init__(self):
self.lock = threading.Lock()
self.observers = {}
def subscribe(self, observer, event_type):
with self.lock:
if event_type not in self.observers:
self.observers[event_type] = set()
self.observers[event_type].add(observer)
def unsubscribe(self, observer, event_type):
with self.lock:
if event_type in self.observers and observer in self.observers[event_type]:
self.observers[event_type].remove(observer)
if not self.observers[event_type]:
del self.observers[event_type]
def notify(self, event_type, message):
with self.lock:
observers_snapshot = list(self.observers.get(event_type, []))
for observer in observers_snapshot:
observer.update(event_type, message)
subject = Subject()
obs1 = Observer('Obs1')
obs2 = Observer('Obs2')
subject.subscribe(obs1, 'eventA')
subject.subscribe(obs2, 'eventB')
subject.notify('eventA', 'Hello A')
subject.notify('eventB', 'Hello B')
subject.unsubscribe(obs1, 'eventA')
subject.notify('eventA', 'Hello again A')
What is printed?Solution
Step 1: Trace subscriptions and notifications
Obs1 subscribes to 'eventA', Obs2 to 'eventB'. First notify('eventA') calls Obs1.update, printing "Obs1 received eventA: Hello A". Then notify('eventB') calls Obs2.update, printing "Obs2 received eventB: Hello B".Step 2: Trace unsubscribe and final notification
Obs1 unsubscribes from 'eventA'. The final notify('eventA') finds no observers, so no output for Obs1. Therefore, the last notification does not print anything.Final Answer:
Option D -> Option DQuick Check:
Unsubscribed observers do not receive notifications [OK]
- Assuming unsubscribed observers still get notified
Solution
Step 1: Understand the problem requirement
The goal is to create a new object where nested mutable fields are independent, so changes in the copy do not affect the original.Step 2: Evaluate approaches
Manual shallow copy (A) shares nested references, causing side effects. Greedy selective copying (B) is not a standard approach and risks missing nested objects. JSON serialization (D) can lose methods and fail on special objects. Recursive deep copy (C) ensures all nested objects are duplicated, preserving independence.Final Answer:
Option D -> Option DQuick Check:
Deep copy duplicates nested objects -> no shared references [OK]
- Assuming shallow copy suffices for nested mutable fields
Solution
Step 1: Embedding snakes/ladders inside Board
This approach simplifies initial design but tightly couples Board to these elements.Step 2: Impact on extensibility
Tightly coupled design makes it harder to add new board elements (e.g., portals, traps) without modifying Board.Step 3: Modeling as separate entities
Allows easy extension by adding new element types without changing Board internals.Step 4: Complexity and memory considerations
Separate entities add minimal overhead; runtime complexity impact is negligible.Final Answer:
Option B -> Option BQuick Check:
Trade-off is between simplicity and extensibility, not runtime complexity or memory bloat.
- Thinking separate entities cause big runtime overhead
- Believing embedding improves encapsulation and immutability
- Assuming separate entities cause memory bloat
Solution
Step 1: Identify the data structure and notification process
Observers are stored per event type in sets. Notification locks and copies only the observers for the specific event type.Step 2: Analyze complexity of notify()
Notify creates a snapshot list of observers for the event type (size k) and iterates over it, so time is proportional to k, not total n.Final Answer:
Option B -> Option BQuick Check:
Notify cost depends only on observers for that event type [OK]
- Assuming notify iterates over all observers regardless of event type
