← 返回题目列表

什么是模板方法模式?它解决什么问题?

高频 简单 第 2 / 26 题 更新于 2026/07/28
模板方法模式行为型模式算法骨架设计模式

简化版

模板方法模式是在父类中定义一个算法流程的骨架,把其中某些可变步骤延迟到子类实现。它主要解决“流程固定但部分步骤变化”的问题,能复用公共流程,同时约束子类按统一顺序执行。

详细版

模板方法模式属于行为型设计模式,核心思想是:父类控制整体流程,子类只负责实现或扩展某些步骤。

典型结构是:

  1. 抽象父类定义模板方法,也就是固定流程。
  2. 父类把流程拆成多个步骤方法。
  3. 通用步骤由父类实现。
  4. 可变步骤由子类实现。
  5. 可选步骤可以用钩子方法控制。

例如文件导入流程通常是固定的:读取文件、校验数据、转换格式、保存数据、记录结果。不同文件类型的校验和转换可能不同,但整体顺序不能乱。这种场景就适合模板方法模式。

它的价值是复用流程代码、避免重复实现、保证执行顺序一致。但它依赖继承,父类和子类耦合较强,使用时要避免父类过于庞大。

完整版教学

一、先抓住模板方法模式的关键词

模板方法模式有两个关键词:固定骨架、延迟步骤。

固定骨架指的是流程顺序由父类决定。例如:

准备数据 -> 校验数据 -> 执行业务 -> 保存结果 -> 收尾处理

延迟步骤指的是父类不关心某些步骤的具体实现,而是交给子类完成。

这就像做菜的流程通常固定:备菜、烹饪、装盘。但不同菜的烹饪细节不同。模板方法模式就是把“做菜流程”放到父类,把“具体怎么炒”交给子类。

二、为什么不直接复制流程代码

如果没有模板方法模式,不同业务类可能各自写一套类似流程:

read();
validate();
transform();
save();
log();

一开始看起来没问题,但流程多了以后会有几个问题:

  • 公共步骤重复;
  • 流程顺序可能不一致;
  • 修改公共逻辑要改很多地方;
  • 子类容易漏掉必要步骤;
  • 流程边界不清晰。

模板方法模式把公共流程上收到父类,子类只填可变部分,能减少重复和流程漂移。

三、模板方法通常要声明为 final

模板方法就是流程入口,常见写法是:

public abstract class DataImporter {
    public final void importData() {
        readFile();
        validate();
        transform();
        save();
        afterImport();
    }
}

把模板方法声明为 final 的目的是防止子类改写流程顺序。因为模板方法模式的核心价值之一就是父类控制流程。

当然,不是所有语言或所有项目都必须写 final,但面试中可以说明:如果希望严格约束流程,模板方法应该避免被子类重写。

四、哪些步骤交给子类

父类可以把步骤分成三类:

  1. 固定步骤:所有子类都一样,由父类实现。
  2. 抽象步骤:每个子类必须不同,由子类实现。
  3. 钩子步骤:子类可选择覆盖,用于扩展或控制流程。

例如:

protected abstract void validate();

protected void afterImport() {
    // 默认空实现,子类需要时覆盖
}

这样父类既能固定主流程,又能给子类留下扩展点。

五、模板方法模式适合什么变化

模板方法模式适合“流程稳定,步骤变化”。

它不适合“整个算法都可以自由替换”的场景。如果不同实现之间流程差异很大,强行用模板方法会让父类塞满钩子和条件判断,反而不好维护。

判断是否适合,可以问两个问题:

  1. 多个实现是否有相同流程顺序?
  2. 差异是否集中在少数步骤?

如果答案是肯定,模板方法模式就很自然。

六、骨架稳定、步骤可变的边界

三个导入任务都固定执行“校验→解析→落库→汇总”4 步,只有解析和落库实现不同;父类保留 4 步顺序,子类只实现 2 个变化点。

client -> final template() -> validate -> parse* -> save* -> summarize

这里真正需要保护的是父类掌握的流程不变量:客户端只能进入模板入口,子类只能改写约定好的步骤。评审时应逐步标出哪些行为固定、哪些行为必须实现、哪些行为只是可选钩子,避免父类和子类互相猜测。

七、继承边界与流程契约验证

检查维度应确认的内容
机制正确性模板方法复用的是算法骨架,不是把所有业务都塞进抽象父类。
适用边界流程顺序经常变化或需要运行时自由组合时,继承骨架会变成束缚,应考虑策略、管道或责任链。
测试证据记录步骤进入与退出序列,覆盖默认钩子、覆写钩子、步骤异常和清理路径
工程代价重点评估父类改动会影响多少子类、protected 扩展面有多大,以及新增变化是否迫使无关子类一起修改

易错点:模板方法复用的是算法骨架,不是把所有业务都塞进抽象父类。

八、常见误区与追问

  • 误区:模板方法就是一个普通的工具方法。 关键在于父类定义稳定骨架并通过多态调用可变步骤,单纯公共方法复用不构成该模式。
  • 误区:模板方法要求所有步骤都由子类覆写。 稳定步骤应在父类直接实现;只有必要变化点才做抽象步骤,可选变化点才做有默认实现的钩子。
  • 追问:怎样判断流程是否足够稳定可以抽模板? 观察多个实现的步骤顺序和不变量是否长期一致;若变化轴主要在少数步骤,才适合上移骨架。
  • 追问:模板方法为什么常声明为 final? 为了防止子类改写算法骨架和步骤顺序;若框架有意允许重写,则必须明确不变量和扩展契约。
  • 追问:模板方法最关键的回归测试是什么? 是父类契约测试:所有子类都必须满足固定步骤顺序、公共前后置行为和异常清理规则。

九、加强记忆

模板方法模式要记成“父类定流程,子类填步骤”。它适合流程骨架稳定、局部步骤变化的场景,能复用公共逻辑并保证执行顺序;但因为依赖继承,要避免父类过重和子类被迫适配无关步骤。