模板方法模式(Template Method Pattern):固定算法骨架,灵活定制步骤
模板方法模式是行为型设计模式的一种,核心思想是在抽象类中定义一个算法的骨架(模板方法),将算法中可变的步骤延迟到子类中实现,使得子类在不改变算法整体结构的前提下,可自定义某些特定步骤。这种模式就像 “文档模板”—— 模板规定了文档的整体结构(如标题、正文、结尾),用户只需填充具体内容即可,核心是 “固定骨架,灵活填充”。
模板方法模式的核心结构

模板方法模式通过抽象类和子类的配合实现算法的复用与扩展,包含三种关键方法:
模板方法(Template Method)
- 定义在抽象类中,描述算法的骨架,按顺序调用其他方法(抽象方法、钩子方法),构成完整的算法流程。
- 通常用
final修饰,防止子类修改算法结构。 - 示例:
makeBeverage()(制作饮料的模板方法,依次调用 “煮水→冲泡→倒杯→加配料”)。
抽象方法(Abstract Method)
- 由抽象类声明、子类必须实现的方法,对应算法中可变的步骤。
- 示例:
brew()(冲泡,咖啡和茶的冲泡方式不同)、addCondiments()(加配料,咖啡加奶,茶加糖)。
钩子方法(Hook Method)
- 由抽象类声明并提供默认实现(可为空),子类可选择重写,用于控制算法流程或添加额外逻辑。
- 示例:
isAddCondiments()(是否加配料,子类可通过返回false跳过该步骤)。
代码实现示例
以 “饮料制作流程” 为例,展示模板方法模式的实现:咖啡和茶的制作流程基本相同(煮水→冲泡→倒杯→加配料),但冲泡方式和配料不同,通过模板方法固定流程,子类实现差异步骤。
1. 抽象类(定义模板方法和抽象方法)
1 | // 抽象类:饮料制作模板 |
2. 具体子类(实现抽象方法,可选重写钩子方法)
1 | // 具体子类1:咖啡 |
3. 客户端使用
1 | public class TemplateMethodDemo { |
模板方法模式的核心优势
- 固定算法结构,复用公共逻辑
抽象类中的模板方法固定了算法的整体流程,公共步骤(如煮水、倒杯)在抽象类中实现,避免子类重复编码,提高代码复用性。 - 灵活扩展可变步骤
子类通过实现抽象方法自定义可变步骤(如咖啡和茶的不同冲泡方式),符合开闭原则(扩展时无需修改模板方法)。 - 控制子类扩展
模板方法用final修饰,确保子类无法修改算法结构;钩子方法允许子类在特定节点扩展,既灵活又可控。 - 封装不变,扩展可变
清晰区分算法中的不变部分(模板方法和固定步骤)与可变部分(抽象方法和钩子方法),逻辑层次分明。
适用场景
- 算法流程固定,步骤部分可变
当多个类的算法流程基本一致,仅部分步骤存在差异时(如:- 流程类业务:登录流程(输入账号→验证→授权→跳转,验证方式可变)。
- 框架回调:如 Spring 的
InitializingBean(afterPropertiesSet()方法在初始化后固定调用)。 - 测试用例:单元测试的
setUp()→test()→tearDown()流程,test()方法可变。
- 需要控制子类扩展
当希望子类仅能在特定步骤扩展,而不改变整体流程时(如线程池ThreadPoolExecutor的beforeExecute()和afterExecute()钩子方法)。 - 重构重复代码
当多个子类存在重复的流程代码时,可将流程提取为模板方法,差异步骤抽象为抽象方法,减少冗余。
优缺点分析
优点
- 代码复用率高:公共流程在抽象类中实现,避免重复编码。
- 扩展性好:新增功能只需添加子类,实现抽象方法即可。
- 算法结构稳定:模板方法固定流程,确保子类遵循统一的算法逻辑。
缺点
- 灵活性受限:子类必须遵循模板方法定义的流程,无法改变步骤顺序。
- 抽象类与子类耦合:子类的实现依赖抽象类的模板方法,若模板方法修改,可能影响所有子类。
- 学习成本:新手可能难以理解 “骨架与步骤” 的分离设计。
经典应用案例
- Java 集合框架的
AbstractListAbstractList定义了get()、size()等抽象方法,模板方法indexOf()、lastIndexOf()基于这些抽象方法实现,子类(如ArrayList、LinkedList)只需实现核心抽象方法即可复用模板方法。 - Spring 的
AbstractApplicationContext
Spring 容器初始化流程(refresh()方法)是典型的模板方法,包含 “准备刷新→获取 bean 工厂→加载 bean 定义→初始化 bean” 等步骤,部分步骤通过钩子方法(如postProcessBeanFactory())允许子类扩展。 - JUnit 的测试用例
JUnit4 的TestCase类中,runBare()方法作为模板方法,按setUp()→runTest()→tearDown()顺序执行,runTest()为抽象方法,由用户编写具体测试逻辑。 - 线程池
ThreadPoolExecutorThreadPoolExecutor的execute()方法定义了任务执行的流程,beforeExecute()、afterExecute()等钩子方法允许子类在任务执行前后添加自定义逻辑(如日志记录、监控)。
总结
模板方法模式通过 “抽象类定义骨架,子类实现步骤” 的方式,完美平衡了算法的稳定性与灵活性。其核心价值在于复用公共流程,同时允许子类定制差异步骤,特别适合流程固定但细节可变的场景。在框架设计中,模板方法模式被广泛应用,如 Spring、JUnit 等,通过定义模板方法为用户提供扩展点,同时确保框架的核心流程稳定