← 返回题目列表

使用模板方法模式有哪些常见误区?

高频 困难 第 16 / 26 题 更新于 2026/07/28
模板方法模式常见误区过度设计继承

简化版

模板方法模式常见误区包括:流程不稳定也强行抽父类、抽象步骤过多导致子类被迫空实现、钩子方法泛滥、父类变成上帝类、子类绕过模板方法直接调用步骤,以及把所有代码复用都理解成继承复用。

详细版

使用模板方法模式要避免这些问题:

  1. 流程本身经常变化,却强行固定在父类;
  2. 父类抽象过宽,子类实现大量无关方法;
  3. 钩子方法太多,流程变得难以预测;
  4. 父类承担太多业务细节,变成上帝类;
  5. 模板方法没有限制重写,子类随意改变流程;
  6. 步骤方法暴露过多,外部绕过模板流程调用;
  7. 继承层次过深,维护成本越来越高;
  8. 明明需要运行时组合,却选择了继承。

面试中可以强调:模板方法适合稳定流程,不适合复杂多变流程;设计时要控制抽象步骤数量,模板方法最好保持稳定和清晰。

完整版教学

一、误区一:流程不稳定还强行抽模板

模板方法模式的前提是流程骨架稳定。

如果不同子类流程差异很大,父类为了兼容它们就会不断增加判断和钩子:

if (needStepA()) {
    stepA();
}
if (needStepB()) {
    stepB();
}

最后模板方法会变得很难读。

这种情况下,可能应该用策略模式、责任链模式或显式流程编排,而不是继续往父类塞扩展点。

二、误区二:抽象步骤过多

父类如果定义太多抽象方法,子类就会被迫实现很多自己不关心的方法。

例如:

protected abstract void stepA();
protected abstract void stepB();
protected abstract void stepC();
protected abstract void stepD();

某些子类可能只需要 stepA,但仍要实现其他步骤,最后写一堆空方法。

这说明抽象层次可能有问题。可以把非必需步骤改成钩子方法,或者拆分不同模板父类。

三、误区三:钩子方法泛滥

钩子方法很方便,但太多会让流程不可预测。

读父类时,你会看到很多可选点;读子类时,又要到处找它覆盖了哪些钩子。

如果一个模板方法需要大量钩子才能工作,说明这个流程抽象不够稳定。

钩子方法应该少而关键,名字要清晰,默认行为要安全。

四、误区四:父类变成上帝类

模板父类应该负责公共流程,不应该吞下所有业务细节。

如果父类里既有订单逻辑、支付逻辑、库存逻辑,又有各种子类特判,它就不再是模板,而是难以维护的上帝类。

父类应该依赖抽象步骤,而不是识别具体子类。

如果父类出现大量:

if (this instanceof SomeSubclass)

基本说明设计已经坏了。

五、误区五:模板方法没有保护流程

如果模板方法可以被子类随意重写,那么流程就失去了约束。

很多场景下,模板方法应该声明为 final,步骤方法则用 protected 留给子类。

此外,步骤方法不要随便暴露给外部调用。外部应该调用模板方法,而不是直接调用某个内部步骤。

六、误区六:把继承当成唯一复用方式

模板方法是继承复用,但现代工程里通常更谨慎地使用继承。

如果变化维度很多,组合往往更灵活。

例如不同导入流程既有不同文件格式,又有不同校验规则、不同保存目标、不同通知方式。强行用继承会导致子类组合爆炸。

这时可以用模板方法固定大流程,再把某些变化步骤委托给策略对象。

七、用不变量审查抽象父类

审查一个含 8 个步骤、6 个钩子的父类时,先标出必须固定的步骤;若只有 2 步真正稳定,说明模板骨架抽得过早。

compare flows -> identify invariants -> minimal hooks -> contract tests

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

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

检查维度应确认的内容
机制正确性模板方法的质量取决于不变量是否真实稳定,而不是抽象方法数量是否足够多。
适用边界父类不应读取所有子类的业务字段,也不应让构造过程调用可覆写方法,否则可能在子类初始化完成前动态分派。
测试证据构造最小子类覆盖每个钩子组合,验证父类不变量、异常清理和禁止绕过的入口
工程代价重点评估父类改动会影响多少子类、protected 扩展面有多大,以及新增变化是否迫使无关子类一起修改

易错点:模板方法的质量取决于不变量是否真实稳定,而不是抽象方法数量是否足够多。

九、常见误区与追问

  • 误区:在父类构造器中调用钩子可以减少初始化代码。 可覆写方法可能访问尚未初始化的子类字段,产生难以定位的半初始化错误。
  • 误区:模板方法要求所有步骤都由子类覆写。 稳定步骤应在父类直接实现;只有必要变化点才做抽象步骤,可选变化点才做有默认实现的钩子。
  • 追问:如何验证模板没有被子类破坏? 除子类单测外,还要建立父类契约测试,校验步骤顺序、异常清理和所有实现共有的不变量。
  • 追问:模板方法为什么常声明为 final? 为了防止子类改写算法骨架和步骤顺序;若框架有意允许重写,则必须明确不变量和扩展契约。
  • 追问:模板方法最关键的回归测试是什么? 是父类契约测试:所有子类都必须满足固定步骤顺序、公共前后置行为和异常清理规则。

十、加强记忆

模板方法模式的误区可以记成“流程不稳别抽、抽象别太宽、钩子别太多、父类别太重、流程别被子类改乱”。它适合稳定骨架,不适合把所有变化都塞进继承体系。