模板方法模式(Template Method Pattern),定义一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构,即可重定义该算法的某些特定步骤。
模板方法模式的核心思想是“好莱坞原则”——“不要调用我们,我们会调用你(Don't call us, we'll call you)”。父类定义好一套固定的算法执行流程,而将其中多变的具体环节留给子类去实现,实现了代码复用与流程控制的统一。
优缺点
优点
- 代码复用,减少冗余: 将公共步骤与算法骨架抽取到父类中,子类只需关注自身特殊的业务逻辑。
- 锁定流程,规范行为: 父类统筹控制整体算法结构,防止子类无意破坏或修改算法的执行顺序。
- 符合开闭原则(OCP): 增加新的算法实现只需新增一个子类,扩展方便,不影响原有的父类与其他子类。
缺点
- 类数量增加: 每一个不同的具体实现都需要定义一个子类,可能导致系统中的类数量膨胀。
- 反向控制带来阅读成本: 子类方法被父类调用,对于不熟悉继承链的代码阅读者来说,理解代码执行流程相对困难。
- 骨架修改影响较大: 一旦父类的模板方法结构发生变动,所有子类都会受到波及。
举个例子
制作冲泡饮料(Beverage),整体流程都是固定的:
烧水 -> 冲泡 -> 倒入杯中-> 加调味料
其中 烧开水 和 倒入杯中 是所有饮料通用的步骤;而 冲泡 与 加调味料 则由具体饮料自行决定。此外,还可以通过 “钩子(Hook)” 决定是否要加调味料。
代码实现
// 抽象父类:定义算法骨架
public abstract class Beverage {
// 模板方法:定义整体流程(用 final 修饰,防止子类颠倒或修改步骤)
public final void makeBeverage() {
boilWater();
brew();
pourInCup();
// 通过钩子方法控制是否执行某个步骤
if (customerWantsCondiments()) {
addCondiments();
}
}
// 通用具体步骤 1:烧水
private void boilWater() {
System.out.println("将水烧开到 100℃");
}
// 通用具体步骤 2:倒进杯子
private void pourInCup() {
System.out.println("倒入杯中");
}
// 抽象步骤 1:冲泡(子类必须实现)
protected abstract void brew();
// 抽象步骤 2:加调味料(子类必须实现)
protected abstract void addCondiments();
// 钩子方法(Hook):默认提供标准逻辑,子类可按需重写Override
protected boolean customerWantsCondiments() {
return true;
}
}
// 具体子类 1:咖啡
public class Coffee extends Beverage {
@Override
protected void brew() {
System.out.println("用滤纸萃取咖啡粉");
}
@Override
protected void addCondiments() {
System.out.println("加入牛奶和糖");
}
}
// 具体子类 2:茶(重写钩子,不加调料)
public class Tea extends Beverage {
@Override
protected void brew() {
System.out.println("用沸水浸泡茶叶");
}
@Override
protected void addCondiments() {
System.out.println("加入柠檬片");
}
// 重写钩子:原味茶不加调味料
@Override
protected boolean customerWantsCondiments() {
return false;
}
}
客户端调用
public class Client {
public static void main(String[] args) {
System.out.println("=== 制作咖啡 ===");
Beverage coffee = new Coffee();
coffee.makeBeverage();
System.out.println("\\n=== 制作原味茶 ===");
Beverage tea = new Tea();
tea.makeBeverage();
}
}
=== 制作咖啡 ===
将水烧开到 100℃
用滤纸萃取咖啡粉
倒入杯中
加入牛奶和糖
=== 制作原味茶 ===
将水烧开到 100℃
用沸水浸泡茶叶
倒入杯中
模板方法模式的组成要素
适用场景
- 固定流程骨架: 多个子类有通用的处理流程,但具体细节不同(例如:数据导入/导出流程、订单结算流程)。
- 框架开发与扩展点设计: 框架定义好生命周期,开发者只需填写实现代码 (如 Spring 中的 JdbcTemplate,Servlet 中的 HttpServlet.service() 与 doGet()/doPost())。
- 重构抽取公共代码: 当发现多个类中存在大量重复的代码逻辑、且执行步骤顺序高度一致时,可将公共部分抽离至父类模板中。
网硕互联帮助中心



评论前必须登录!
注册