← 返回题目列表

模板方法模式的优缺点是什么?

高频 中等 第 3 / 26 题 更新于 2026/07/28
模板方法模式优缺点继承代码复用

简化版

模板方法模式的优点是复用公共流程、固定执行顺序、把变化步骤交给子类扩展;缺点是依赖继承导致父子类耦合较强,父类修改影响面大,子类过多或钩子过多时会增加维护成本。

详细版

模板方法模式的优点:

  1. 公共流程只写一份,减少重复代码;
  2. 父类统一控制流程顺序;
  3. 子类只关注变化步骤;
  4. 符合一定程度的开闭原则;
  5. 适合框架定义扩展点。

模板方法模式的缺点:

  1. 基于继承,父子类耦合强;
  2. 父类流程变化会影响所有子类;
  3. 子类数量可能膨胀;
  4. 抽象步骤设计不好会迫使子类实现无关方法;
  5. 钩子方法太多会让流程难理解。

面试中要补一句:模板方法适合流程稳定的场景,如果流程本身经常变化,或者需要运行时灵活组合行为,策略模式等组合方式可能更合适。

完整版教学

一、优点一:复用公共流程

模板方法模式最直接的好处是减少重复。

如果多个类都要执行相同流程:

参数校验 -> 业务执行 -> 记录日志 -> 释放资源

就可以把这些公共流程放到父类。子类只实现真正不同的业务步骤。

这样公共逻辑修改时,只需要改父类。

二、优点二:保证流程顺序一致

有些流程不能让子类随意改。

例如数据库操作必须先获取连接,再执行 SQL,最后释放资源。如果每个子类都自己写流程,就容易漏掉释放资源。

模板方法由父类统一控制顺序,可以避免子类破坏流程。

这也是模板方法常用于框架的原因:框架希望用户扩展,但不希望用户改乱主流程。

三、优点三:扩展点清晰

父类可以明确告诉子类哪些地方必须实现,哪些地方可以选择性覆盖。

抽象方法表示必须实现的变化点,钩子方法表示可选扩展点。

这种结构比让子类自由发挥更可控。

四、缺点一:父子类耦合强

模板方法模式依赖继承。继承意味着子类和父类之间绑定比较紧。

父类流程改动,所有子类都可能受影响。

如果父类越来越复杂,子类要理解父类内部流程才能正确实现步骤,维护成本会变高。

五、缺点二:抽象设计不好会让子类难受

如果父类抽象了太多步骤,所有子类都被迫实现,即使某些子类不需要这些步骤,也要写空实现。

这说明父类抽象可能过宽。

可以考虑:

  • 把非必需步骤改成钩子方法;
  • 拆分多个模板父类;
  • 使用组合方式替代继承;
  • 重新划分业务流程边界。

六、缺点三:钩子太多会让流程失控

钩子方法本来是灵活扩展点,但如果父类里布满钩子,读代码时就很难判断实际流程。

比如每个步骤前后都有钩子,每个步骤是否执行也靠钩子控制,这会让父类像一个小型流程引擎。

如果变化这么多,模板方法可能不是最佳选择。

七、复用收益和继承耦合的量化

6 个子类共享 40 行骨架可减少约 200 行重复,但父类新增 1 个抽象步骤会迫使 6 个子类同时修改。

benefit: one skeleton; cost: N subclasses coupled to base contract

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

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

检查维度应确认的内容
机制正确性模板方法把流程控制集中到父类,同时把扩展自由限制在少数步骤,这是有意的交换。
适用边界子类多且变化点稳定时收益明显;抽象父类频繁变动时,修改扩散会抵消复用价值。
测试证据记录步骤进入与退出序列,覆盖默认钩子、覆写钩子、步骤异常和清理路径
工程代价重点评估父类改动会影响多少子类、protected 扩展面有多大,以及新增变化是否迫使无关子类一起修改

易错点:模板方法把流程控制集中到父类,同时把扩展自由限制在少数步骤,这是有意的交换。

九、常见误区与追问

  • 误区:模板方法一定比复制代码更易维护。 若抽象错误或流程不稳定,父类变化会产生更大范围的连锁修改。
  • 误区:模板方法要求所有步骤都由子类覆写。 稳定步骤应在父类直接实现;只有必要变化点才做抽象步骤,可选变化点才做有默认实现的钩子。
  • 追问:怎样评估钩子是否过多? 当理解一次执行需要组合多个钩子状态,或子类依赖隐含调用顺序时,应重构扩展模型。
  • 追问:模板方法为什么常声明为 final? 为了防止子类改写算法骨架和步骤顺序;若框架有意允许重写,则必须明确不变量和扩展契约。
  • 追问:模板方法最关键的回归测试是什么? 是父类契约测试:所有子类都必须满足固定步骤顺序、公共前后置行为和异常清理规则。

十、加强记忆

模板方法模式的优点是复用流程、固定顺序、扩展点清晰;缺点是继承耦合强、父类变化影响大、子类和钩子过多会难维护。它适合流程稳定、变化点明确的场景。