行为型模式 - 模板方法模式

文章目录

  • [1. 生活中的例子](#1. 生活中的例子)
    • [1.1 做菜的标准流程 🍳](#1.1 做菜的标准流程 🍳)
    • [1.2 银行的办事流程 🏦](#1.2 银行的办事流程 🏦)
    • [1.3 搭乐高玩具 🧱](#1.3 搭乐高玩具 🧱)
  • [2. 代码中的例子](#2. 代码中的例子)
    • [2.1 制作饮料的模板 ☕️](#2.1 制作饮料的模板 ☕️)
    • [2.2 数据处理的模板 📊](#2.2 数据处理的模板 📊)
    • [2.3 简单的游戏框架 🎮](#2.3 简单的游戏框架 🎮)
  • [3. 归纳总结](#3. 归纳总结)
    • [3.1 核心思想](#3.1 核心思想)
    • [3.2 关键点总结表](#3.2 关键点总结表)
    • [3.3 什么时候使用模板方法模式](#3.3 什么时候使用模板方法模式)
    • [3.4 如果没有模板方法模式](#3.4 如果没有模板方法模式)

1. 生活中的例子

1.1 做菜的标准流程 🍳

想象你妈妈教你做菜:

  1. 妈妈告诉你:所有菜都要按这个顺序做:洗菜 → 切菜 → 开火 → 下锅 → 装盘
  2. 西红柿炒蛋青椒肉丝 具体做法不同:
    • 西红柿炒蛋:切西红柿 → 打鸡蛋 → 先炒蛋 → 再炒西红柿
    • 青椒肉丝:切青椒 → 切肉丝 → 一起下锅炒
  3. 核心 :妈妈给了你固定流程(模板),具体每个步骤怎么实现,你自己决定

1.2 银行的办事流程 🏦

你去银行办理业务:

  1. 固定流程:取号 → 等待叫号 → 到窗口 → 办理业务 → 评价服务
  2. 但不同业务的具体内容不同:
    • 存款:填存款单 → 交钱 → 拿回单
    • 取款:填取款单 → 输密码 → 拿钱
  3. 核心 :银行规定了办事的标准流程,具体业务内容你自己处理

1.3 搭乐高玩具 🧱

每个乐高玩具的搭建说明:

  1. 固定模式:打开包装 → 分类零件 → 按图纸搭底座 → 搭主体 → 装饰
  2. 但不同的乐高:
    • 城堡:先搭城墙 → 再搭塔楼
    • 汽车:先搭底盘 → 再装轮子
  3. 核心 :乐高给了你搭建的框架,具体搭什么由图纸决定

2. 代码中的例子

2.1 制作饮料的模板 ☕️

java 复制代码
// 抽象类:定义饮料制作的模板
abstract class BeverageMaker {
    
    // 模板方法(固定流程,用final防止被子类修改)
    public final void prepareBeverage() {
        boilWater();        // 1.烧水(固定步骤)
        brew();             // 2.冲泡(由子类实现)
        pourInCup();        // 3.倒入杯子(固定步骤)
        addCondiments();    // 4.加调料(由子类实现)
        hook();             // 5.钩子方法(可选步骤)
    }
    
    // 固定步骤1
    private void boilWater() {
        System.out.println("正在烧水...");
    }
    
    // 固定步骤3
    private void pourInCup() {
        System.out.println("倒入杯子中");
    }
    
    // 抽象方法:必须由子类实现
    protected abstract void brew();          // 冲泡方式
    protected abstract void addCondiments(); // 添加调料
    
    // 钩子方法:子类可以选择是否覆盖
    protected void hook() {
        // 默认什么都不做
    }
}

// 具体实现1:泡茶
class TeaMaker extends BeverageMaker {
    @Override
    protected void brew() {
        System.out.println("用80℃水泡茶叶3分钟");
    }
    
    @Override
    protected void addCondiments() {
        System.out.println("加入一片柠檬");
    }
    
    @Override
    protected void hook() {
        System.out.println("倒茶前先用热水温杯");
    }
}

// 具体实现2:冲咖啡
class CoffeeMaker extends BeverageMaker {
    @Override
    protected void brew() {
        System.out.println("用92℃水冲泡咖啡粉");
    }
    
    @Override
    protected void addCondiments() {
        System.out.println("加入牛奶和糖");
    }
    // 注意:这里没有覆盖hook()方法,所以使用默认实现(什么都不做)
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        System.out.println("=== 泡茶 ===");
        BeverageMaker tea = new TeaMaker();
        tea.prepareBeverage();
        
        System.out.println("\n=== 冲咖啡 ===");
        BeverageMaker coffee = new CoffeeMaker();
        coffee.prepareBeverage();
    }
}

2.2 数据处理的模板 📊

java 复制代码
// 抽象模板:数据处理流程
abstract class DataProcessor {
    
    // 模板方法:固定数据处理流程
    public final void processData() {
        readData();         // 1.读取数据
        transformData();    // 2.转换数据(由子类实现)
        validateData();     // 3.验证数据(固定步骤)
        saveData();         // 4.保存数据(由子类实现)
    }
    
    // 固定步骤
    private void validateData() {
        System.out.println("验证数据完整性...");
    }
    
    // 抽象方法
    protected abstract void readData();
    protected abstract void transformData();
    protected abstract void saveData();
}

// 具体实现:从文件读取数据
class FileDataProcessor extends DataProcessor {
    @Override
    protected void readData() {
        System.out.println("从CSV文件读取数据");
    }
    
    @Override
    protected void transformData() {
        System.out.println("清洗和过滤数据");
    }
    
    @Override
    protected void saveData() {
        System.out.println("保存到数据库");
    }
}

// 具体实现:从API读取数据
class APIDataProcessor extends DataProcessor {
    @Override
    protected void readData() {
        System.out.println("从REST API获取数据");
    }
    
    @Override
    protected void transformData() {
        System.out.println("将JSON转换为对象");
    }
    
    @Override
    protected void saveData() {
        System.out.println("保存到云存储");
    }
}

2.3 简单的游戏框架 🎮

java 复制代码
// 游戏模板
abstract class Game {
    
    // 模板方法:游戏运行流程
    public final void play() {
        initialize();    // 1.初始化游戏
        startPlay();     // 2.开始游戏(由子类实现)
        endPlay();       // 3.结束游戏(由子类实现)
        showScore();     // 4.显示分数(固定步骤)
    }
    
    // 固定步骤
    private void initialize() {
        System.out.println("初始化游戏资源...");
    }
    
    private void showScore() {
        System.out.println("显示最终得分");
    }
    
    // 抽象方法
    protected abstract void startPlay();
    protected abstract void endPlay();
}

// 具体游戏1:象棋
class Chess extends Game {
    @Override
    protected void startPlay() {
        System.out.println("象棋开始:红方先行");
    }
    
    @Override
    protected void endPlay() {
        System.out.println("象棋结束:将军!");
    }
}

// 具体游戏2:足球游戏
class FootballGame extends Game {
    @Override
    protected void startPlay() {
        System.out.println("足球比赛开始:开球!");
    }
    
    @Override
    protected void endPlay() {
        System.out.println("足球比赛结束:哨声响起");
    }
}

3. 归纳总结

3.1 核心思想

"不要重复造轮子,但可以自定义零件"

3.2 关键点总结表

概念 比喻 代码对应
模板方法 做菜的固定流程 prepareBeverage()
抽象方法 必须自己做的步骤 brew(), addCondiments()
具体方法 已经帮你做好的步骤 boilWater(), pourInCup()
钩子方法 可选的额外步骤 hook()

3.3 什么时候使用模板方法模式

✅ 使用场景:

  1. 多个类有相同的流程 ,但某些步骤实现不同
  2. 需要控制子类的扩展,只允许修改特定步骤
  3. 想要避免代码重复,把公共代码提取到父类

❌ 不适合场景:

  1. 每个类的流程完全不同(没有共同模板)
  2. 步骤顺序经常变化(模板不稳定)

记住三句话:

  1. 模板方法是骨架:父类定义"做什么"和"顺序"
  2. 具体方法是血肉:子类定义"怎么做"的细节
  3. 钩子方法是装饰:可选的自定义扩展点

3.4 如果没有模板方法模式

请你想象一下:如果没有模板方法模式,泡茶和泡咖啡的代码会怎样?

  • 你会写两个几乎一样的类
  • 每次修改流程都要改两个地方
  • 容易出错,维护困难

有了模板方法模式

  • 流程统一管理,修改一次全部生效
  • 代码复用,避免重复
  • 结构清晰,易于维护

这就是模板方法模式的魔力!🎯

相关推荐
zhaokuner8 小时前
06-聚合与一致性边界-DDD领域驱动设计
java·开发语言·设计模式·架构
技术小泽9 小时前
DDD领域设计精讲
java·后端·设计模式·架构
Geoking.9 小时前
简单工厂模式介绍
设计模式·简单工厂模式
zhaokuner10 小时前
08-仓储与映射-DDD领域驱动设计
java·开发语言·设计模式·架构
会员果汁11 小时前
7.设计模式-模板方法模式
算法·设计模式·模板方法模式
zhaokuner11 小时前
01-领域与问题空间-DDD领域驱动设计
java·开发语言·设计模式·架构
崎岖Qiu11 小时前
【设计模式笔记26】:深入浅出「观察者模式」
java·笔记·观察者模式·设计模式
zhaokuner12 小时前
02-通用语言与协作-DDD领域驱动设计
java·开发语言·设计模式·架构
会员果汁12 小时前
9.设计模式-建造者模式
设计模式·建造者模式