引言
本文用一杯茶咖,让你喝懂模板方法模式设计思想
☕ “程序员不止写代码,也懂泡茶和冲咖啡。”
模板方法模式——把固定的流程封装在抽象类中,把可变的步骤交给子类决定。本文通过生活化例子+代码一一对应讲透它!
一、模板方法模式定义
模板方法模式(Template Method Pattern)是一种行为型设计模式,用于定义一个操作中的算法骨架,而将一些步骤的实现延迟到子类中。
通俗地说:
父类定流程,子类补细节。
这使得子类在不改变整体算法结构的前提下,能够重新定义某些步骤的实现方式。
二、类比用例
在生活中,泡茶与冲咖啡为例来理解这一设计模式。
泡茶与冲咖啡的流程都很像:
- 烧开水
- 冲泡
- 倒入杯中
- 如果愿意,可以加入佐料(如柠檬片、糖、牛奶等)
于是,我们可以把这套流程抽象为一个“饮品冲泡模板”,具体细节(茶叶 or 咖啡粉,是否加佐料)由子类决定。
三、模板方法模式结构
@startuml
abstract class CaffeineBeverage {
+prepareRecipe()
-boilWater()
-pourInCup()
+brew() : abstract
+addCondiments() : abstract
}
class Tea extends CaffeineBeverage
class Coffee extends CaffeineBeverage
CaffeineBeverage <|-- Tea
CaffeineBeverage <|-- Coffee
@enduml
四、代码实现:把生活变代码
4.1. 饮品冲泡模板(抽象类)
public abstract class CaffeineBeverage {
// 模板方法,不可重写
public final void prepareRecipe() {
boilWater();
brew(); // 由子类实现
pourInCup();
if (customerWantsCondiments()) {
addCondiments(); // 由子类实现
}
}
void boilWater() {
System.out.println("把水煮沸");
}
void pourInCup() {
System.out.println("把饮料倒进杯子");
}
// 钩子方法:子类可以选择是否重写
boolean customerWantsCondiments() {
return true;
}
abstract void brew(); // 冲泡方式不同
abstract void addCondiments(); // 添加佐料方式不同
}
4.2. 茶类实现
public class Tea extends CaffeineBeverage {
@Override
void brew() {
System.out.println("用热水浸泡茶叶");
}
@Override
void addCondiments() {
System.out.println("加点柠檬片");
}
@Override
boolean customerWantsCondiments() {
return true; // 或根据用户输入来动态判断
}
}
4.3. 咖啡类实现
public class Coffee extends CaffeineBeverage {
@Override
void brew() {
System.out.println("用热水冲泡咖啡粉");
}
@Override
void addCondiments() {
System.out.println("加糖和牛奶");
}
@Override
boolean customerWantsCondiments() {
return false; // 咖啡师决定不加
}
}
4.4. 客户端享用
public class BeverageTestDrive {
public static void main(String[] args) {
System.out.println("---------- 泡一杯茶 ----------");
CaffeineBeverage tea = new Tea();
tea.prepareRecipe();
System.out.println("\n---------- 冲一杯咖啡 ----------");
CaffeineBeverage coffee = new Coffee();
coffee.prepareRecipe();
}
}
输出结果:
---------- 泡一杯茶 ----------
把水煮沸
用热水浸泡茶叶
把饮料倒进杯子
加点柠檬片
---------- 冲一杯咖啡 ----------
把水煮沸
用热水冲泡咖啡粉
把饮料倒进杯子
五、关键点分析
步骤 | 属于抽象类 | 属于子类 | 是否可扩展 |
---|---|---|---|
boilWater() |
✅ | ❌ | ❌ |
brew() |
❌ | ✅ | ✅ |
addCondiments() |
❌ | ✅ | ✅ |
prepareRecipe() |
✅(final) | ❌ | ❌ |
customerWantsCondiments() |
✅(钩子) | ✅(可重写) | ✅(灵活) |
六、优缺点总结
模板方法模式:
把流程写死在抽象类,把差异开放给子类,
这样就能稳定结构,又自由扩展。
优点
- 提高代码复用性:公共流程只写一次,子类只专注差异化实现。
- 提高扩展性:子类可按需定制部分步骤。
- 实现**“开闭原则”**:结构稳定,细节可变。
缺点
- 增加了类的数量(每种实现都要新建类)
- 对类结构理解有一定要求,不适合流程极度不确定的场景
七、应用场景
模板方法常见于以下场景:
- 框架设计:如 Servlet 的
doGet()
/doPost()
在service()
中被调用。 - 数据处理流程:读取文件 → 解析 → 验证 → 存储。
- 游戏或AI算法中的行为模板。
八、附加建议:代码增强思路
- 增加用户交互
Scanner
控制是否加佐料 - 用
Logger
代替System.out.println
- 封装为“饮品工厂”模式组合使用