✓ Decorators wrap objects to add behavior dynamically without subclassing.
This is hard to see from code alone because the wrapping and delegation happen at runtime and are invisible in static class hierarchies.
✓ Method calls delegate through the decorator chain, accumulating behavior step-by-step.
Visualizing each call clarifies how each decorator contributes to the final result.
✓ Stacking multiple decorators composes complex behavior flexibly and transparently.
The trace shows how each decorator wraps the previous one, enabling modular extensions.
Practice
(1/5)
1. Consider the following code snippet implementing the Command Pattern with undo/redo stacks. After executing the commands: Add 5, Add 3, Undo, Redo, what is the final state of the receiver?
easy
A. 5
B. 8
C. 3
D. 0
Solution
Step 1: Trace command executions
Execute Add 5 -> state = 5; Execute Add 3 -> state = 8.
Step 2: Trace undo and redo
Undo removes Add 3 -> state reverts to 5; Redo reapplies Add 3 -> state returns to 8.
Final Answer:
Option B -> Option B
Quick Check:
State after redo is 8 [OK]
Hint: Undo then redo restores the last undone command [OK]
Common Mistakes:
Forgetting redo reapplies the command
Off-by-one in stack operations
2. Which of the following statements about handling concurrency in the Library Management System's LoanManager is INCORRECT?
medium
A. Optimistic locking is unsuitable because it always leads to deadlocks in high contention scenarios.
B. Using pessimistic locking on book records ensures no two users can borrow the same book simultaneously.
C. Implementing atomic check-and-update operations prevents race conditions during loan processing.
D. Using version numbers or timestamps can help detect conflicting updates in optimistic concurrency control.
Solution
Step 1: Understand pessimistic locking
Pessimistic locking prevents concurrent conflicting access, so Using pessimistic locking on book records ensures no two users can borrow the same book simultaneously. is correct.
Step 2: Why optimistic locking is not always deadlock?
Optimistic locking is unsuitable because it always leads to deadlocks in high contention scenarios. is incorrect; optimistic locking reduces deadlocks by retrying on conflicts.
Step 3: Atomic operations prevent race conditions
Implementing atomic check-and-update operations prevents race conditions during loan processing. is correct and essential for concurrency safety.
Step 4: Versioning aids optimistic concurrency
Using version numbers or timestamps can help detect conflicting updates in optimistic concurrency control. correctly describes conflict detection mechanisms.
Final Answer:
Option A -> Option A
Quick Check:
Optimistic locking reduces deadlocks; it does not always cause them.
3. Examine the following buggy CompositeIterator code snippet. Which line contains the subtle bug that causes incorrect traversal order?
medium
A. Line initializing self.stack without reversing children.
B. Line checking hasNext() before popping from stack.
C. Line popping component from stack.
D. Line returning the component after processing.
Solution
Step 1: Identify stack initialization issue
Stack is initialized with children in original order, not reversed, causing traversal order reversal.
Step 2: Confirm impact on traversal order
Without reversing, popping from stack yields children in reverse order, breaking expected traversal.
Final Answer:
Option A -> Option A
Quick Check:
Reversing children on stack initialization fixes traversal order [OK]
Hint: Stack must reverse children to preserve traversal order [OK]
Common Mistakes:
Forgetting to reverse children on stack push
Misplacing hasNext() check
4. What is the time complexity of notifying observers in the thread-safe observer pattern implementation where observers are stored in a dictionary mapping event types to sets of observers, and a snapshot list is created during notification?
medium
A. O(n) where n is total number of all observers across all event types
B. O(k) where k is the number of observers subscribed to the notified event type
C. O(k + n) where k is observers for event type and n is total observers
D. O(1) constant time due to hash set usage
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 B
Quick Check:
Notify cost depends only on observers for that event type [OK]
Hint: Notify complexity depends on observers for event type only [OK]
Common Mistakes:
Assuming notify iterates over all observers regardless of event type
5. If a class exposes a public getter but no setter for a private field, what is a likely reason an interviewer would probe this design choice?
hard
A. To test if the candidate thinks public fields are better than getters
B. To confirm that the candidate knows getters always require setters
C. To verify that the candidate believes private fields should never be exposed
D. To check if the candidate understands immutability and controlled read-only access
Solution
Step 1: Understand getter-only design
Getter without setter implies read-only access, often for immutability or controlled exposure.
Step 2: Analyze interviewer intent
Interviewer probes if candidate recognizes design for immutability or encapsulation control.
Step 3: Evaluate incorrect options
To confirm that the candidate knows getters always require setters is false; setters are not always required. To verify that the candidate believes private fields should never be exposed is extreme; exposing read-only data is common. To test if the candidate thinks public fields are better than getters is a misconception favoring public fields.
Final Answer:
Option D -> Option D
Quick Check:
Getter-only design supports immutability and controlled access.
Hint: Getter-only means read-only, not incomplete encapsulation [OK]