Understanding the Template Method Design Pattern with Java Examples
This article explains the Template Method design pattern, illustrating its structure with Java drink‑making examples, discussing hook methods, and showing real‑world usages in JDK’s Comparable and Spring’s ApplicationContext, while highlighting advantages, drawbacks, and practical scenarios.
Introduction
Template Method is a behavioral design pattern that defines the skeleton of an algorithm in a superclass while allowing subclasses to override specific steps without changing the overall structure.
Scenario Example
Using a beverage shop analogy, the article first shows a naive interface‑based design and then refactors it into an abstract class Drinks with a final method makingDrinks() that outlines the fixed steps (boil water, brew, pour, add condiments). The invariant steps are implemented in the abstract class, while the variable steps are declared abstract for subclasses.
<code style="padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px"><span style="color: #c678dd; line-height: 26px">public</span> <span style="color: #c678dd; line-height: 26px">abstract</span> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">class</span> <span style="color: #e6c07b; line-height: 26px">Drinks</span> </span>{<br/><br/> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">void</span> <span style="color: #61aeee; line-height: 26px">boilWater</span><span style="line-height: 26px">()</span> </span>{<br/> System.out.println(<span style="color: #98c379; line-height: 26px">"将水煮沸"</span>);<br/> }<br/><br/> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">abstract</span> <span style="color: #c678dd; line-height: 26px">void</span> <span style="color: #61aeee; line-height: 26px">brew</span><span style="line-height: 26px">()</span></span>;<br/><br/> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">void</span> <span style="color: #61aeee; line-height: 26px">pourInCup</span><span style="line-height: 26px">()</span> </span>{<br/> System.out.println(<span style="color: #98c379; line-height: 26px">"倒入杯子"</span>);<br/> }<br/><br/> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">abstract</span> <span style="color: #c678dd; line-height: 26px">void</span> <span style="color: #61aeee; line-height: 26px">addCondiments</span><span style="line-height: 26px">()</span></span>;<br/> <br/> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">public</span> <span style="color: #c678dd; line-height: 26px">final</span> <span style="color: #c678dd; line-height: 26px">void</span> <span style="color: #61aeee; line-height: 26px">makingDrinks</span><span style="line-height: 26px">()</span> </span>{<br/> <span style="color: #5c6370; font-style: italic; line-height: 26px">//热水</span><br/> boilWater();<br/> <span style="color: #5c6370; font-style: italic; line-height: 26px">//冲泡</span><br/> brew();<br/> <span style="color: #5c6370; font-style: italic; line-height: 26px">//倒进杯子</span><br/> pourInCup();<br/> <span style="color: #5c6370; font-style: italic; line-height: 26px">//加料</span><br/> addCondiments();<br/> }<br/>}<br/></code>Concrete subclasses Tea and Coffee extend Drinks and implement the abstract methods to provide specific brewing and condiment logic.
<code style="padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px"><span style="color: #c678dd; line-height: 26px">public</span> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">class</span> <span style="color: #e6c07b; line-height: 26px">Tea</span> <span style="color: #c678dd; line-height: 26px">extends</span> <span style="color: #e6c07b; line-height: 26px">Drinks</span> </span>{<br/> <span style="color: #61aeee; line-height: 26px">@Override</span><br/> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">void</span> <span style="color: #61aeee; line-height: 26px">brew</span><span style="line-height: 26px">()</span> </span>{<br/> System.out.println(<span style="color: #98c379; line-height: 26px">"冲茶叶"</span>);<br/> }<br/> <span style="color: #61aeee; line-height: 26px">@Override</span><br/> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">void</span> <span style="color: #61aeee; line-height: 26px">addCondiments</span><span style="line-height: 26px">()</span> </span>{<br/> System.out.println(<span style="color: #98c379; line-height: 26px">"加柠檬片"</span>);<br/> }<br/>}<br/></code> <code style="padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px"><span style="color: #c678dd; line-height: 26px">public</span> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">class</span> <span style="color: #e6c07b; line-height: 26px">Coffee</span> <span style="color: #c678dd; line-height: 26px">extends</span> <span style="color: #e6c07b; line-height: 26px">Drinks</span> </span>{<br/> <span style="color: #61aeee; line-height: 26px">@Override</span><br/> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">void</span> <span style="color: #61aeee; line-height: 26px">brew</span><span style="line-height: 26px">()</span> </span>{<br/> System.out.println(<span style="color: #98c379; line-height: 26px">"冲咖啡粉"</span>);<br/> }<br/><br/> <span style="color: #61aeee; line-height: 26px">@Override</span><br/> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">void</span> <span style="color: #61aeee; line-height: 26px">addCondiments</span><span style="line-height: 26px">()</span> </span>{<br/> System.out.println(<span style="color: #98c379; line-height: 26px">"加奶加糖"</span>);<br/> }<br/>}<br/></code>A main method demonstrates creating Coffee and Tea objects and invoking makingDrinks() to see the template in action.
<code style="padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px"><span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">public</span> <span style="color: #c678dd; line-height: 26px">static</span> <span style="color: #c678dd; line-height: 26px">void</span> <span style="color: #61aeee; line-height: 26px">main</span><span style="line-height: 26px">(String[] args)</span> </span>{<br/> Drinks coffee = <span style="color: #c678dd; line-height: 26px">new</span> Coffee();<br/> coffee.makingDrinks();<br/> System.out.println();<br/> Drinks tea = <span style="color: #c678dd; line-height: 26px">new</span> Tea();<br/> tea.makingDrinks();<br/>}<br/></code>Hook Method
The article introduces a hook method customerLike() that can be overridden by subclasses to decide whether to add condiments, demonstrating how optional steps can be controlled.
<code style="padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px"><span style="color: #c678dd; line-height: 26px">public</span> <span style="color: #c678dd; line-height: 26px">abstract</span> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">class</span> <span style="color: #e6c07b; line-height: 26px">Drinks</span> </span>{<br/><br/> ...<br/><br/> <span style="color: #c678dd; line-height: 26px">public</span> <span style="color: #c678dd; line-height: 26px">final</span> <span style="color: #c678dd; line-height: 26px">void</span> <span style="color: #61aeee; line-height: 26px">makingDrinks</span><span style="line-height: 26px">()</span> {<br/> boilWater();<br/> brew();<br/> pourInCup();<br/> <span style="color: #5c6370; font-style: italic; line-height: 26px">//如果顾客需要,才加料</span><br/> <span style="color: #c678dd; line-height: 26px">if</span> (customerLike()) {<br/> addCondiments();<br/> }<br/> }<br/><br/> <span style="color: #5c6370; font-style: italic; line-height: 26px">//默认实现,返回 true</span><br/> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">boolean</span> <span style="color: #61aeee; line-height: 26px">customerLike</span><span style="line-height: 26px">()</span> </span>{<br/> <span style="color: #c678dd; line-height: 26px">return</span> <span style="color: #c678dd; line-height: 26px">true</span>;<br/> }<br/>}<br/></code>Real‑World Uses
JDK Comparable
Implementing Comparable requires defining compareTo(), which is called by Collections.sort() or Arrays.sort(). The sorting algorithm is a template method that invokes the user‑provided compareTo for each comparison.
<code style="padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px"><span style="color: #c678dd; line-height: 26px">public</span> <span style="color: #c678dd; line-height: 26px">int</span> <span style="color: #61aeee; line-height: 26px">compareTo</span><span style="line-height: 26px">(Object o)</span> {<br/> Coffee coffee = (Coffee)o;<br/> if(this.price < coffee.price) <span style="color: #c678dd; line-height: 26px">return</span> -1;<br/> else if(this.price == coffee.price) <span style="color: #c678dd; line-height: 26px">return</span> 0;<br/> else <span style="color: #c678dd; line-height: 26px">return</span> 1;<br/>}<br/></code>Spring ApplicationContext
Spring’s AbstractApplicationContext.refresh() method is a classic template method. It defines the overall container startup workflow while delegating specific steps (e.g., getBeanFactory(), refreshBeanFactory()) to subclasses and providing hook points such as postProcessBeanFactory().
<code style="padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px"><span style="color: #c678dd; line-height: 26px">public</span> <span style="color: #c678dd; line-height: 26px">abstract</span> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">class</span> <span style="color: #e6c07b; line-height: 26px">AbstractApplicationContext</span> <span style="color: #c678dd; line-height: 26px">extends</span> <span style="color: #e6c07b; line-height: 26px">DefaultResourceLoader</span> {<br/> <span style="color: #61aeee; line-height: 26px">@Override</span><br/> <span style="color: #c678dd; line-height: 26px">public</span> <span style="color: #c678dd; line-height: 26px">void</span> <span style="color: #61aeee; line-height: 26px">refresh</span><span style="line-height: 26px">()</span> {<br/> synchronized(this.startupShutdownMonitor){<br/> prepareRefresh();<br/> ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();<br/> prepareBeanFactory(beanFactory);<br/> postProcessBeanFactory(beanFactory);<br/> // … other steps …<br/> finishRefresh();<br/> }<br/> }<br/> <span style="color: #c678dd; line-height: 26px">protected</span> <span style="color: #c678dd; line-height: 26px">void</span> <span style="color: #61aeee; line-height: 26px">postProcessBeanFactory</span>(ConfigurableListableBeanFactory beanFactory){ }<br/>}<br/></code>Summary
Advantages: encapsulates invariant parts, promotes code reuse, and centralizes algorithm control in the superclass.
Disadvantages: each variation requires a new subclass, potentially increasing class count and system complexity.
When to use: multiple subclasses share a common algorithm structure, or a complex method benefits from being broken into a fixed template with customizable steps.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
