Template Method: fix the workflow
Picture
Read values, validate them, transform them, then return a result. Different importers may vary only the transform step.
Predict
How does Template Method differ from a supplied Strategy object?
Walk through the small example
It varies steps through inheritance. Strategy usually supplies a collaborator; Template Method exposes subclass hooks.
Mental model and complete Python solution
Importer.run is the template: snapshot input, validate integer values, then invoke transform. Doubler overrides the transform hook. The example uses abc to prevent instantiating a class that lacks the required operation. Inheritance couples the subclass to the base workflow, so prefer composition when independent runtime swapping is the main requirement.
What the function promises: run accepts an iterable of integers and returns transformed values. Invalid inputs fail before transform is called.
from abc import ABC, abstractmethod
class Importer(ABC):
def run(self, values):
values = list(values)
if any(type(value) is not int for value in values):
raise ValueError("Only integers are supported")
return self.transform(values)
@abstractmethod
def transform(self, values):
pass
class Doubler(Importer):
def transform(self, values):
return [2 * value for value in values]
assert Doubler().run([1, 3]) == [2, 6]
assert Doubler().run([]) == []
Work and storage: O(n) validation and transformation in this example, with O(n) copied storage.
When to recognize it: A subclass must honor validation and output expectations. Inheritance does not excuse breaking the caller’s contract.
Check before applying it: Subclass hooks remain bound by the base class’s behavioral contract.
Change one rule
The transform must change per request without changing object type. What alternative fits?
See what changes
Inject a strategy function or object into a stable importer. Composition makes that runtime variation explicit and avoids constructing a subclass for every rule.
Connect
Keep changes from spreading everywhere: Subclass hooks must preserve the base caller’s contract.
Swap the rule, not the whole feature: Compare inheritance hooks with a composed, replaceable policy.