The abstract base class CaffeineBeverage is defined with the template method 'prepare_recipe' that calls steps boil_water, brew, pour_in_cup, and conditionally add_condiments. Abstract methods brew and add_condiments are declared.
💡 This step establishes the algorithm skeleton that subclasses will follow and override. Understanding this structure is key to grasping the pattern.
💡 The template method defines the fixed sequence of steps, enforcing the algorithm's structure.
setup
Setup: Define Subclass Tea with Overrides
The Tea subclass overrides the abstract methods brew and add_condiments, and also overrides the hook method customer_wants_condiments to disable condiments.
💡 This step shows how subclasses customize specific steps and optionally disable parts of the algorithm via hooks.
💡 Subclass overrides complete the algorithm customization by providing specific condiments.
final_state
Final State: Template Method Pattern Execution Complete
Both Tea and Coffee have executed their prepare_recipe methods. Tea skipped condiments due to hook override; Coffee included condiments. The algorithm skeleton was preserved by the base class.
💡 This final step summarizes how the template method pattern enforces algorithm structure while allowing subclass customization.
💡 The pattern separates invariant algorithm steps from variant ones, promoting reuse and flexibility.
Template Method Pattern - Define Skeleton, Override Steps - Watch the Algorithm Execute, Step by Step
Watching each step of the template method execution reveals how inheritance and method overriding work together to enforce a consistent algorithm structure while allowing flexible customization.
Step 1/14
·Active fill★Answer cell
Defines the template method pattern skeleton with abstract and concrete steps.
«abstract»CaffeineBeverage
+prepare_recipe()
+boil_water()
+brew()
+3 more
Subclass overrides abstract steps and hook to customize behavior.
Tea
+brew()
+add_condiments()
+customer_wants_condiments()
«abstract»CaffeineBeverage
Tea ▷ CaffeineBeverage
Subclass overrides abstract steps but uses default hook to include condiments.
Coffee
+brew()
+add_condiments()
«abstract»CaffeineBeverage
Coffee ▷ CaffeineBeverage
Template method calls concrete step boil_water from base class.
Tea
+prepare_recipe()
+boil_water()
«abstract»CaffeineBeverage
Tea ▷ CaffeineBeverage
Subclass method brew overrides abstract step.
Tea
+brew()
«abstract»CaffeineBeverage
Tea ▷ CaffeineBeverage
Base class concrete method pour_in_cup reused.
Tea
+pour_in_cup()
«abstract»CaffeineBeverage
Tea ▷ CaffeineBeverage
Hook method controls optional step execution.
Tea
+customer_wants_condiments()
«abstract»CaffeineBeverage
Tea ▷ CaffeineBeverage
Optional step pruned by hook decision.
Tea
+add_condiments()
«abstract»CaffeineBeverage
Tea ▷ CaffeineBeverage
Template method calls concrete step boil_water from base class.
Template Method pattern enforces algorithm skeleton with subclass customization via overrides and hooks.
«abstract»CaffeineBeverage
+prepare_recipe()
+boil_water()
+brew()
+3 more
Tea
+brew()
+add_condiments()
+customer_wants_condiments()
Coffee
+brew()
+add_condiments()
Tea ▷ CaffeineBeverageCoffee ▷ CaffeineBeverage
Key Takeaways
✓ The template method defines a fixed algorithm skeleton, ensuring consistent execution order.
This insight is hard to see from code alone because the flow is split across base and subclasses; visualization shows the enforced sequence clearly.
✓ Subclasses override abstract steps to customize parts of the algorithm without changing its structure.
Seeing the method calls and overrides step-by-step reveals how polymorphism enables flexible behavior.
✓ Hook methods allow subclasses to enable or disable optional steps dynamically, pruning the algorithm flow.
The conditional execution controlled by hooks is subtle in code but becomes obvious when watching the decision and pruning steps.
Practice
(1/5)
1. What is the time complexity of computing the cost() method when stacking k decorators on a core object using the Decorator Pattern with dynamic behavior injection?
medium
A. O(1) because each decorator adds a fixed cost
B. O(k) because each decorator delegates the call to the next one
C. O(k^2) because each decorator calls all previous decorators recursively
D. O(log k) because decorators form a balanced tree structure
Solution
Step 1: Identify call chain length
Each decorator's cost() calls the wrapped object's cost(), forming a chain of length k.
Step 2: Calculate total calls
Cost computation requires traversing all k decorators once, so time complexity is O(k).
Final Answer:
Option B -> Option B
Quick Check:
Each decorator adds constant work, total linear in k [OK]
Hint: Decorator calls chain length equals number of decorators [OK]
Common Mistakes:
Assuming O(1) because cost is a simple addition
Mistaking recursive calls as quadratic
2. When designing the Library Management System, what is a key trade-off when using inheritance to model different types of library items (e.g., books, magazines, DVDs) versus using composition with a common Item interface?
medium
A. Composition leads to code duplication but improves runtime performance due to fewer indirections
B. Inheritance simplifies code reuse but reduces flexibility to add new item types without modifying base classes
C. Inheritance allows dynamic behavior changes at runtime, while composition fixes behavior at compile time
D. Composition forces all item types to share the same data fields, limiting customization
Solution
Step 1: Understand inheritance trade-offs
Inheritance promotes reuse but creates tight coupling and fragile base classes.
Step 2: Why not composition causes duplication?
Composition leads to code duplication but improves runtime performance due to fewer indirections is incorrect; composition reduces duplication by delegating behavior.
Step 3: Why not inheritance allows runtime behavior changes?
Inheritance allows dynamic behavior changes at runtime, while composition fixes behavior at compile time is false; composition better supports runtime behavior changes via delegation.
Step 4: Why not composition forces shared fields?
Composition forces all item types to share the same data fields, limiting customization is wrong; composition allows flexible data encapsulation per type.
Final Answer:
Option B -> Option B
Quick Check:
Inheritance trades flexibility for reuse; composition trades reuse for flexibility.
Hint: Inheritance = reuse but rigid; Composition = flexible but needs delegation [OK]
Common Mistakes:
Confusing runtime flexibility between inheritance and composition
Assuming composition causes code duplication
Believing composition forces uniform data fields
3. Which of the following statements about access modifiers and encapsulation is INCORRECT?
medium
A. Protected members are accessible by any class in the same package regardless of inheritance
B. Private members are accessible only within the defining class
C. Public members are accessible from any other class
D. Using private access modifier enforces data hiding
Solution
Step 1: Recall access modifier rules
Private: class-only; Protected: subclass and package; Public: everywhere.
Step 2: Analyze Protected members are accessible by any class in the same package regardless of inheritance
Protected members are accessible within the same package and subclasses, but not by any class in the package regardless of inheritance.
Step 3: Validate other options
Options B, C, and D correctly describe access modifiers and encapsulation.
Final Answer:
Option A -> Option A
Quick Check:
Protected access is limited to subclasses and package, not all classes in package indiscriminately.
Hint: Protected ≠ accessible by all classes in package, only subclasses and package [OK]
Common Mistakes:
Confusing protected with package-private
Assuming private allows subclass access
Believing public restricts access
4. Suppose you want to extend the Command Pattern to support commands that can be executed multiple times (reused) and also support undo/redo correctly. Which modification to the invoker's undo/redo management is necessary to handle this scenario without corrupting state?
hard
A. Store only one instance of each command and reuse it for all executions, pushing it multiple times onto undo stack.
B. Clear both undo and redo stacks after every command execution to avoid reuse issues.
C. Create a new command instance for each execution and push that instance onto the undo stack, ensuring undo/redo operate on the correct state snapshot.
D. Avoid using undo/redo stacks and instead recompute state from scratch on each undo or redo.
Solution
Step 1: Understand reuse implications
Reusing the same command instance for multiple executions causes undo/redo to affect the wrong state because the command's internal state may change.
Step 2: Identify correct approach
Creating a new command instance per execution ensures each undo/redo corresponds to the exact executed command instance and its parameters.
Step 3: Confirm undo/redo stack integrity
This approach preserves correct ordering and state consistency during undo/redo operations.
Final Answer:
Option C -> Option C
Quick Check:
New instances per execution prevent state corruption on undo/redo [OK]
Hint: Each execution needs a fresh command instance for correct undo/redo [OK]
Common Mistakes:
Reusing command instances causing incorrect undos
Clearing stacks unnecessarily losing history
5. In a large-scale system where behaviors need to be dynamically changed at runtime, what is a key design consideration when using composition to avoid pitfalls that inheritance-based designs face?
hard
A. Use deep inheritance hierarchies to capture all behavior variations upfront.
B. Ensure that composed behavior objects are immutable to prevent side effects.
C. Avoid using interfaces and rely on concrete classes to reduce complexity.
D. Design behavior interfaces and use delegation so behaviors can be swapped without modifying the main object.
Solution
Step 1: Understand dynamic behavior change
To change behaviors at runtime, the design must support swapping behavior implementations easily.
Step 2: Analyze options
Ensure that composed behavior objects are immutable to prevent side effects. is not practical; immutability limits dynamic changes. Avoid using interfaces and rely on concrete classes to reduce complexity. increases coupling and reduces flexibility. Use deep inheritance hierarchies to capture all behavior variations upfront. contradicts favoring composition and leads to rigid designs.
Step 3: Confirm best practice
Design behavior interfaces and use delegation so behaviors can be swapped without modifying the main object. promotes defining behavior interfaces and delegating calls, enabling runtime swapping without modifying main objects.
Final Answer:
Option D -> Option D
Quick Check:
Delegation with interfaces is key to flexible, dynamic composition.
Hint: Use interfaces and delegation to swap behaviors dynamically, not inheritance or concrete classes.
Common Mistakes:
Thinking immutability aids dynamic behavior changes
Relying on inheritance for runtime flexibility
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.