Java模板模式案例如何编写:从理论到实战的完整指南
目录导读
- 模板模式是什么?为什么你需要它?
- 模板模式的核心结构与UML图解
- 一个完整的Java模板模式案例(含代码)
- 案例详解:从咖啡到茶的制作流程模拟
- 模板模式在Spring框架中的真实应用
- 常见问题与最佳实践(含问答)
- 何时选用模板模式?
模板模式是什么?为什么你需要它?
问:模板模式(Template Method Pattern)是什么? 答:模板模式是一种行为型设计模式,它在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中实现,模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些特定步骤。

问:为什么Java开发中经常使用模板模式? 答:因为它能有效消除重复代码,提高复用性,例如在Web开发、批处理、数据访问层中,当多个业务流程拥有相似的步骤但细节不同时,模板模式可以让你把通用流程固定下来,让子类只关心变化的部分。
核心思想:父类定义“做什么”,子类定义“怎么做”,父类中的模板方法通常被声明为final,防止子类修改整个流程。
模板模式的核心结构与UML图解
模板模式主要由以下角色组成:
| 角色 | 名称 | 职责 |
|---|---|---|
| 抽象类(AbstractClass) | 定义模板方法,包含一个或多个抽象操作/钩子方法 | 定义算法骨架 |
| 具体子类(ConcreteClass) | 实现抽象类中的抽象方法 | 完成特定步骤 |
UML简示:
AbstractClass
├── templateMethod() ← final,不可重写
│ ├── stepOne() ← 抽象方法
│ ├── stepTwo() ← 具体方法(默认实现)
│ ├── hookMethod() ← 钩子方法(可选覆盖)
│ └── stepThree() ← 抽象方法
ConcreteClassA → 实现stepOne()、stepThree()
ConcreteClassB → 实现stepOne()、stepThree(),并覆盖hookMethod()
关键点:
- 模板方法(
templateMethod())用final修饰,确保算法结构不变。 - 抽象方法由子类强制实现。
- 钩子方法(Hook)提供默认空实现,子类可选择是否覆盖。
一个完整的Java模板模式案例(含代码)
案例背景:饮料制作流程
我们模拟两种饮料:咖啡和茶,它们的制作步骤非常相似:
- 烧水
- 冲泡饮品
- 倒入杯子
- 添加调料
其中步骤1和3完全相同,步骤2和4因饮料不同而异。
代码实现
第一步:定义抽象类 Beverage
public abstract class Beverage {
// 模板方法,声明为final防止子类修改流程
public final void prepareRecipe() {
boilWater(); // 烧水
brew(); // 冲泡(抽象方法)
pourInCup(); // 倒入杯子
addCondiments(); // 添加调料(抽象方法)
}
private void boilWater() {
System.out.println("烧开水");
}
private void pourInCup() {
System.out.println("将饮品倒入杯子");
}
// 抽象方法:子类必须实现
protected abstract void brew();
protected abstract void addCondiments();
}
第二步:创建具体子类 Coffee
public class Coffee extends Beverage {
@Override
protected void brew() {
System.out.println("用沸水冲泡咖啡粉");
}
@Override
protected void addCondiments() {
System.out.println("加入糖和牛奶");
}
}
第三步:创建具体子类 Tea
public class Tea extends Beverage {
@Override
protected void brew() {
System.out.println("用热水浸泡茶叶");
}
@Override
protected void addCondiments() {
System.out.println("加入柠檬片");
}
}
第四步:客户端测试
public class TemplatePatternDemo {
public static void main(String[] args) {
Beverage coffee = new Coffee();
Beverage tea = new Tea();
System.out.println("===== 制作咖啡 =====");
coffee.prepareRecipe();
System.out.println("\n===== 制作茶 =====");
tea.prepareRecipe();
}
}
输出结果:
===== 制作咖啡 =====
烧开水
用沸水冲泡咖啡粉
将饮品倒入杯子
加入糖和牛奶
===== 制作茶 =====
烧开水
用热水浸泡茶叶
将饮品倒入杯子
加入柠檬片
案例详解:从咖啡到茶的制作流程模拟
模板方法的执行流程
- 父类
Beverage.prepareRecipe()定义不可变的算法顺序。 - 子类
Coffee和Tea各自实现brew()和addCondiments()。 - 客户端无需关心具体步骤,直接调用
prepareRecipe()即可完成完整流程。
如何扩展这个案例?
假设你希望某些饮料不需要加调料(如白开水),可以在父类中添加一个钩子方法:
// 在父类中添加钩子方法
protected boolean customerWantsCondiments() {
return true; // 默认需要
}
然后在模板方法中条件判断:
public final void prepareRecipe() {
boilWater();
brew();
pourInCup();
if (customerWantsCondiments()) {
addCondiments();
}
}
子类可以重写钩子方法:
public class PlainWater extends Beverage {
@Override
protected void brew() {
// 空白实现,实际就是白开水
}
@Override
protected boolean customerWantsCondiments() {
return false;
}
}
问:钩子方法有什么作用? 答:钩子方法允许子类在不破坏模板方法结构的前提下,控制算法的某些部分是否执行,它是模板模式的“可选项控制开关”。
模板模式在Spring框架中的真实应用
JdbcTemplate 与数据库操作
Spring的JdbcTemplate是模板模式的经典实现,它定义了“获取连接-执行SQL-处理结果-关闭资源”的固定流程,而开发者只需通过回调接口提供SQL语句和结果映射逻辑:
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.query("SELECT * FROM users", new RowMapper<User>() {
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
return user;
}
});
HttpServlet的service()方法
Java Servlet中的HttpServlet类提供了doGet()、doPost()等钩子方法,而service()方法作为模板方法,根据HTTP请求类型调用对应的方法。
在框架源码中的其他案例
- Spring的
AbstractApplicationContext定义了Bean容器的刷新流程。 - MyBatis的
BaseExecutor定义了查询执行的骨架。
常见问题与最佳实践(含问答)
问1:模板模式和策略模式有什么区别? 答:模板模式关注算法结构的复用,通过继承复用相同步骤;策略模式关注算法行为的变换,通过组合实现不同算法,简单说:模板模式是“同一个算法的不同步骤实现”,策略模式是“不同算法的替换”。
问2:模板模式会导致类爆炸吗? 答:如果每一个变化步骤都创建一个新子类,确实可能导致子类过多,建议配合工厂模式或组合模式,或者在子类中通过参数化来控制差异。
问3:什么时候应该避免使用模板模式? 答:当算法步骤数量非常少且稳定时,使用简单继承即可,当算法步骤未来可能频繁增加或减少时,模板模式的“骨架固定性”反而会成为约束。
最佳实践建议:
- 模板方法尽量声明为
final,避免子类意外重写。 - 抽象方法定义为
protected,仅对子类暴露。 - 钩子方法使用
protected和空实现(或默认true),子类按需覆盖。 - 不要在模板方法中添加
if-else判断具体类型,这违背了开闭原则。
何时选用模板模式?
- ✅ 多个类拥有相似的算法骨架,但部分步骤实现不同。
- ✅ 需要控制子类的扩展点,防止子类随意修改流程。
- ✅ 代码重构时,抽取出公共部分,减少重复。
一句话总结:模板模式就像一张“行车路线图”——路线固定,但途中停车点(具体操作)你可以自己规划,掌握它,能让你的Java代码更优雅、更易维护。
本文参考了《Head First 设计模式》、Spring源码官方文档以及多个Java社区的技术分享,经融会贯通后形成此实战指南。