文章目录
-
- [🎯 什么是模板方法模式?一个生动的比喻](#🎯 什么是模板方法模式?一个生动的比喻)
- [☕ 真实生活案例:咖啡厅的饮料制作](#☕ 真实生活案例:咖啡厅的饮料制作)
- [💻 C++代码实现:从菜鸟到高手](#💻 C++代码实现:从菜鸟到高手)
- [🎪 运行效果:像看话剧一样有趣](#🎪 运行效果:像看话剧一样有趣)
- [🧩 模板方法模式的四大核心要点](#🧩 模板方法模式的四大核心要点)
-
- [1. **框架固定,细节灵活**](#1. 框架固定,细节灵活)
- [2. **好莱坞原则:"不要调用我们,我们会调用你"**](#2. 好莱坞原则:"不要调用我们,我们会调用你")
- [3. **代码复用最大化**](#3. 代码复用最大化)
- [4. **便于维护和扩展**](#4. 便于维护和扩展)
- [🌟 实际应用场景(不只是饮料!)](#🌟 实际应用场景(不只是饮料!))
- [📊 模板方法模式 vs 普通继承:有什么区别?](#📊 模板方法模式 vs 普通继承:有什么区别?)
- [🎁 设计模式的"秘密武器"](#🎁 设计模式的"秘密武器")
-
- [钩子方法(Hook Method):给子类留的"后门"](#钩子方法(Hook Method):给子类留的"后门")
- [🚀 为什么要学模板方法模式?](#🚀 为什么要学模板方法模式?)
- [💡 总结:记住这三个关键词](#💡 总结:记住这三个关键词)
🎯 什么是模板方法模式?一个生动的比喻
想象你是一个大厨,要教两个徒弟做菜:一个学做红烧肉,一个学做清蒸鱼。
虽然两道菜完全不同,但烹饪的基本流程却是相通的:
- 准备食材 → 2. 预处理 → 3. 烹饪 → 4. 装盘调味
这个固定的流程就是"模板",而每一步的具体操作就是"方法"。模板方法模式就是:定义一个算法的骨架,让某些步骤由子类去具体实现。
☕ 真实生活案例:咖啡厅的饮料制作
让我们走进一家咖啡厅,看看他们如何高效制作不同饮料:
咖啡师小张的工作流程:
- 🔥 烧开水(必做)
- ☕ 冲泡咖啡粉(咖啡特有)
- 🥛 倒入杯中(必做)
- 🍬 加糖和牛奶(咖啡特有)
茶艺师小李的工作流程:
- 🔥 烧开水(必做)
- 🍵 浸泡茶叶(茶特有)
- 🥛 倒入杯中(必做)
- 🍋 加柠檬(茶特有)
聪明的店长发现:70%的步骤是重复的! 于是她设计了一个"饮料制作模板"...
💻 C++代码实现:从菜鸟到高手
第一步:创建"饮料制作模板"(抽象基类)
cpp
#include <iostream>
#include <memory>
using namespace std;
// 饮料制作模板 - 就像餐厅的标准操作流程
class Beverage {
public:
// 模板方法:这是核心!定义了不可更改的制作流程
void prepareRecipe() final {
cout << "🎬 开始制作饮料..." << endl;
boilWater(); // 第1步:烧水(所有饮料都一样)
brew(); // 第2步:冲泡(每种饮料不同)
pourInCup(); // 第3步:倒杯(所有饮料都一样)
addCondiments(); // 第4步:加料(每种饮料不同)
cout << "✅ 饮料制作完成!" << endl << endl;
}
// 具体步骤1:烧水(不变的部分)
void boilWater() {
cout << "🔥 烧开水中...(等待3分钟)" << endl;
}
// 具体步骤3:倒入杯中(不变的部分)
void pourInCup() {
cout << "🥛 倒入精美的杯子中" << endl;
}
// 抽象步骤2:冲泡(变化的部分)- 等待子类实现
virtual void brew() = 0;
// 抽象步骤4:加调料(变化的部分)- 等待子类实现
virtual void addCondiments() = 0;
virtual ~Beverage() {
cout << "🧹 清理工作台" << endl;
}
};
第二步:实现具体的饮料类
cpp
// 咖啡类 - 继承自饮料模板
class Coffee : public Beverage {
private:
string coffeeType;
public:
Coffee(string type = "拿铁") : coffeeType(type) {}
void brew() override {
cout << "☕ 精心冲泡" << coffeeType << "咖啡粉(专业手法)" << endl;
}
void addCondiments() override {
cout << "🍬 加入特制糖浆和新鲜牛奶" << endl;
}
};
// 茶类 - 继承自饮料模板
class Tea : public Beverage {
private:
string teaType;
public:
Tea(string type = "绿茶") : teaType(type) {}
void brew() override {
cout << "🍵 用85°C热水浸泡" << teaType << "茶叶" << endl;
}
void addCondiments() override {
cout << "🍋 加入新鲜柠檬片" << endl;
}
};
// 新增:热巧克力类(展示扩展性)
class HotChocolate : public Beverage {
public:
void brew() override {
cout = "🍫 融化高品质巧克力块" << endl;
}
void addCondiments() override {
cout << "🧁 加入棉花糖和可可粉装饰" << endl;
}
};
第三步:让我们"开店营业"!
cpp
// 咖啡厅模拟
class CoffeeShop {
public:
void startBusiness() {
cout << "🏪 欢迎光临模板方法咖啡厅!" << endl;
cout << "=================================" << endl;
// 制作咖啡
cout << "📝 订单1:一位客人点了拿铁咖啡" << endl;
unique_ptr<Beverage> coffee = make_unique<Coffee>("拿铁");
coffee->prepareRecipe();
// 制作茶
cout << "📝 订单2:一位客人点了龙井茶" << endl;
unique_ptr<Beverage> tea = make_unique<Tea>("龙井");
tea->prepareRecipe();
// 制作热巧克力
cout << "📝 订单3:小朋友点了热巧克力" << endl;
unique_ptr<Beverage> chocolate = make_unique<HotChocolate>();
chocolate->prepareRecipe();
cout << "=================================" << endl;
cout << "🎉 今天的营业结束,感谢使用模板方法模式!" << endl;
}
};
int main() {
CoffeeShop shop;
shop.startBusiness();
return 0;
}
🎪 运行效果:像看话剧一样有趣
🏪 欢迎光临模板方法咖啡厅!
=================================
📝 订单1:一位客人点了拿铁咖啡
🎬 开始制作饮料...
🔥 烧开水中...(等待3分钟)
☕ 精心冲泡拿铁咖啡粉(专业手法)
🥛 倒入精美的杯子中
🍬 加入特制糖浆和新鲜牛奶
✅ 饮料制作完成!
🧹 清理工作台
📝 订单2:一位客人点了龙井茶
🎬 开始制作饮料...
🔥 烧开水中...(等待3分钟)
🍵 用85°C热水浸泡龙井茶叶
🥛 倒入精美的杯子中
🍋 加入新鲜柠檬片
✅ 饮料制作完成!
🧹 清理工作台
📝 订单3:小朋友点了热巧克力
🎬 开始制作饮料...
🔥 烧开水中...(等待3分钟)
🍫 融化高品质巧克力块
🥛 倒入精美的杯子中
🧁 加入棉花糖和可可粉装饰
✅ 饮料制作完成!
🧹 清理工作台
=================================
🎉 今天的营业结束,感谢使用模板方法模式!
🧩 模板方法模式的四大核心要点
1. 框架固定,细节灵活
- 🏗️ 父类定义"做什么"(算法骨架)
- 🎨 子类定义"怎么做"(具体实现)
2. 好莱坞原则:"不要调用我们,我们会调用你"
父类对子类说:"你只管实现具体步骤,什么时候调用由我来决定!"
3. 代码复用最大化
相同的代码(烧水、倒杯)只写一次,避免"复制粘贴"的罪恶
4. 便于维护和扩展
要修改流程?只需改父类!要新增饮料?只需继承!
🌟 实际应用场景(不只是饮料!)
场景1:游戏开发
cpp
// 所有游戏都有:初始化→主循环→清理
class Game {
void run() final { // 模板方法
initialize();
while(!isGameOver()) {
update();
render();
}
cleanup();
}
// 具体游戏实现抽象方法...
};
场景2:文档处理
cpp
// 所有文档处理:打开→读取→转换→保存
class DocumentProcessor {
void process() final {
openFile();
readContent();
convertFormat(); // 不同格式不同实现
saveFile();
}
};
场景3:测试框架
cpp
// 测试用例模板:准备→执行→验证→清理
class TestCase {
void runTest() final {
setUp();
executeTest();
verifyResult();
tearDown();
}
};
📊 模板方法模式 vs 普通继承:有什么区别?
| 特性 | 普通继承 | 模板方法模式 |
|---|---|---|
| 代码复用 | 部分复用 | ✅ 最大化复用 |
| 流程控制 | 子类控制 | ✅ 父类控制 |
| 扩展性 | 一般 | ✅ 容易扩展 |
| 规范性 | 随意 | ✅ 标准化 |
🎁 设计模式的"秘密武器"
钩子方法(Hook Method):给子类留的"后门"
cpp
class Beverage {
protected:
// 钩子方法:子类可以选择是否重写
virtual bool customerWantsCondiments() {
return true; // 默认加调料
}
void prepareRecipe() final {
boilWater();
brew();
pourInCup();
if (customerWantsCondiments()) { // 使用钩子
addCondiments();
}
}
};
class BlackCoffee : public Beverage {
protected:
bool customerWantsCondiments() override {
return false; // 黑咖啡不加调料
}
};
🚀 为什么要学模板方法模式?
对初学者:
- 📚 理解面向对象:封装、继承、多态的完美结合
- 🧠 培养设计思维:从"怎么写代码"到"怎么设计代码"
对职场人:
- 💼 提高代码质量:减少bug,提高可维护性
- ⏱️ 提升开发效率:避免重复造轮子
对架构师:
- 🏗️ 构建稳定架构:创建可扩展的系统框架
- 🔄 统一开发规范:团队协作更加顺畅
💡 总结:记住这三个关键词
- 模板 - 定义不变的算法骨架
- 方法 - 提供可变的具体实现
- 模式 - 解决特定问题的经验总结
下次当你发现多个类有相似流程时,记得想想:"这里能不能用模板方法模式?"
就像那位聪明的咖啡店长一样,用智慧的设计让代码变得更加优雅和高效!🎯
💡 小练习:你能用模板方法模式设计一个"文件导出工具"吗?支持导出PDF、Excel、Word格式,它们都有:准备数据→格式化→保存文件 的流程。