The Template Method Pattern is a behavioral design pattern that defines the overall structure of an algorithm in a base class while postponing selected implementation details to subclasses. Subclasses can customize individual steps without changing the sequence or control flow of the algorithm.
How the Pattern Is Structured
Abstract class
The abstract class owns the algorithm's framework, usually through a template method that invokes several steps in a fixed order. Some of those steps are abstract and must be implemented by subclasses, while others can provide shared default behavior.
The template method is commonly declared final. This prevents subclasses from replacing the algorithm as a whole and limits customization to the intended extension points.
Concrete subclasses
Concrete subclasses implement the abstract operations defined by the base class. Each subclass supplies the behavior specific to a particular variant while inheriting the common workflow.
When It Fits
The pattern is useful when several classes follow the same general algorithm but differ in a few individual steps. Moving the shared logic into the parent class avoids duplication, while subclasses focus only on the parts that vary.
It is also helpful when a framework needs to control how subclasses extend an algorithm. Instead of allowing arbitrary overrides, the base class can expose only selected operations as customization points.
A Beverage Preparation Example
Consider a process for preparing a drink. The workflow consists of boiling water, brewing the drink, pouring it into a cup, and adding condiments. Brewing and adding condiments vary depending on whether the drink is coffee or tea.
// 抽象类:定义冲泡饮品的模板
abstract class BeverageMaker {
// 模板方法:定义算法骨架,不可被重写
public final void prepareBeverage() {
boilWater();
brew();
pourInCup();
if (customerWantsCondiments()) {
addCondiments();
}
}
// 通用步骤:默认实现
private void boilWater() {
System.out.println("烧开水");
}
// 抽象步骤:由子类实现
protected abstract void brew();
// 通用步骤:默认实现
private void pourInCup() {
System.out.println("倒入杯子");
}
// 抽象步骤:由子类实现
protected abstract void addCondiments();
// 钩子方法:子类可选择性覆盖
protected boolean customerWantsCondiments() {
return true;
}
}
// 具体子类:咖啡
class CoffeeMaker extends BeverageMaker {
@Override
protected void brew() {
System.out.println("用沸水冲泡咖啡");
}
@Override
protected void addCondiments() {
System.out.println("添加糖和牛奶");
}
}
// 具体子类:茶
class TeaMaker extends BeverageMaker {
@Override
protected void brew() {
System.out.println("用沸水浸泡茶叶");
}
@Override
protected void addCondiments() {
System.out.println("添加柠檬");
}
// 覆盖钩子方法,控制是否添加配料
@Override
protected boolean customerWantsCondiments() {
return false;
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
BeverageMaker coffee = new CoffeeMaker();
coffee.prepareBeverage();
System.out.println("\n=====\n");
BeverageMaker tea = new TeaMaker();
tea.prepareBeverage();
}
}
In BeverageMaker, prepareBeverage() is the template method. It fixes the preparation sequence and calls the common and variable steps in the appropriate order.
boilWater()andpourInCup()are shared operations with built-in implementations.brew()andaddCondiments()are abstract operations that each drink maker must define.customerWantsCondiments()is a hook method. It provides a default result, but a subclass can override it to control whether the optional step runs.
CoffeeMaker supplies coffee-specific brewing behavior and adds sugar and milk. TeaMaker defines tea preparation and adds lemon as its condiment implementation, but overrides the hook to return false, so the condiment step is skipped during execution.
Advantages
- Code reuse: Common operations live in the parent class, so subclasses do not need to duplicate them.
- Consistent algorithm control: The template method preserves the workflow and restricts subclasses to the steps designed for customization.
- Targeted extensibility: New subclasses can provide different implementations for selected operations without rewriting the entire process.
Trade-offs
The pattern can increase the number of classes. If every small variation requires a separate subclass, the design may eventually suffer from class proliferation.
There is also a maintenance cost when the template method becomes complicated. A change in the base class can affect every subclass that depends on its workflow, so the shared algorithm should remain clear and reasonably focused.
Common Java Examples
The pattern appears in several familiar Java and Java ecosystem designs:
- In the JDK,
java.util.Collectionsprovidessort()while allowing callers to customize ordering through theComparatorinterface. - In the Servlet API,
HttpServletexposes methods such asdoGet()anddoPost()as extension points for request-specific behavior. - Spring includes template-style classes such as
JdbcTemplateandHibernateTemplate, which centralize common processing while leaving selected operations customizable.
A practical implementation should keep the template method stable—often by declaring it final—and use hook methods deliberately. Hooks add flexibility by letting subclasses influence optional parts of the algorithm, but too many hooks can make the execution path harder to understand.
Template Method works best when the overall procedure is genuinely shared and only a limited number of steps differ. The parent class preserves the common structure, while each subclass concentrates on the behavior that makes its variation distinct.