Template Method
Tea and Coffee classes each write the whole recipe.
Write the recipe once in a base class method (prepare) that calls step methods in a fixed order.
Several classes share the same overall flow but differ in some steps
The picture from life
Making a hot drink follows one recipe: boil water, brew, pour into a cup, add extras. The order never changes. Tea brews by steeping leaves and adds lemon; coffee brews by filtering and adds milk. The recipe card is fixed; only two steps differ.
The problem
What goes wrong when you do not use it.
Tea and Coffee classes each write the whole recipe. The boil and pour steps are copied, and someone fixing a bug in one forgets the other. The order of steps is not guaranteed to match.
- Several classes share the same overall flow but differ in some steps
- You want to control the order in one place
- Duplicate code sits in sibling classes
The idea
How the pattern fixes it.
Write the recipe once in a base class method (prepare) that calls step methods in a fixed order. Shared steps are written in the base; differing steps are abstract and filled in by each subclass.
- extends (is a)
Who is who
- Beverage (base)
- prepare() is the template: boil, brew, pour, add extras.
- brew(), add_extras()
- Abstract steps each subclass must supply.
- Tea, Coffee
- Subclasses that fill the blanks.
Build it in steps
- 1Write the steps in order in one method.
- 2Move the shared steps into the base class.
- 3Declare the varying steps as abstract.
- 4Subclasses implement only those.
Watch it run
Step through the calls. Tap an arrow to jump to it.
prepare() is the template. It lives in Beverage and runs the same steps for every drink.
prepare()The code
Python and Java. Try writing the classes yourself from the diagram first.
class Beverage:
def prepare(self): # the template method: fixed order
return [self.boil_water(), self.brew(), self.pour(), self.add_extras()]
def boil_water(self):
return "boil water"
def pour(self):
return "pour into cup"
def brew(self): # steps the subclasses must fill in
raise NotImplementedError
def add_extras(self):
raise NotImplementedError
class Tea(Beverage):
def brew(self):
return "steep tea leaves"
def add_extras(self):
return "add lemon"
class Coffee(Beverage):
def brew(self):
return "filter coffee"
def add_extras(self):
return "add milk"
def demo():
return Tea().prepare(), Coffee().prepare()What you gain
- Duplicate code moves to one place
- The order of steps is guaranteed
What it costs
- Uses inheritance, so it is rigid
- Many abstract steps make subclasses awkward
You have already met it in
- JUnit's setUp / test / tearDown
- Servlet doGet / doPost inside service()
- Frameworks that call your hooks (Django views, React lifecycle)
Often mixed up with
- StrategyTemplate Method changes steps by inheritance at compile time; Strategy swaps the whole algorithm by composition at run time.
- Factory MethodA Factory Method is often one step inside a Template Method.
Make it stick
Write a DataExporter template: read(), transform(), write(). Make CsvExporter and JsonExporter override only the steps that differ.