模板方法模式核心是“子类只改步骤,不改流程”,即在templatemethod()中锁定稳定执行顺序,将可变环节抽为abstract方法供子类实现;辅以hook方法(可选重写)和final方法(禁止篡改)增强灵活性与安全性。

模板方法模式的核心是“子类只改步骤,不改流程”
它不是让你把所有逻辑都塞进抽象类,而是把稳定不变的执行顺序(比如初始化→处理→收尾)锁死在 templateMethod() 里,把可能变化的环节抽成 abstract 方法留给子类实现。一旦你发现几个类的 execute() 或 run() 方法结构高度相似,只是中间某几步逻辑不同,这就是模板方法最该出手的场景。
常见错误是把本该由子类决定的行为写死在抽象类里,比如在 templateMethod() 中直接调用 new HashMap() 而不是定义 createCache() 让子类选择用 ConcurrentHashMap 还是 LinkedHashMap —— 这样就丧失了扩展性,也违背了开闭原则。
Java 中 abstract 方法必须被子类实现,但 hook 方法可以空着
除了强制子类覆盖的 abstract 方法,你还可以加带默认实现的 protected 方法(叫 hook),比如 beforeProcess() 或 logResult()。子类按需重写,不重写就走空实现或默认日志逻辑。这比硬塞一堆 if (isDebugEnabled) 到主流程里干净得多。
容易踩的坑是把 hook 设计成 public,或者让它返回关键数据——hook 的职责只是“钩住时机”,不该承担主流程的数据流转。如果某个步骤的结果被后续步骤强依赖,那它就不是 hook,得是 abstract 方法。
-
abstract方法:子类必须实现,主流程靠它拿数据、做决策 - hook 方法:子类可选重写,用于日志、监控、清理等副作用操作
- final 方法:放在抽象类里,禁止子类篡改流程节点(比如
validateInput())
Python 里没有 abstract 关键字,靠 ABC 和 NotImplementedError 模拟
Python 没有语言级抽象方法语法,得用 abc.ABC 和 @abstractmethod 装饰器。不继承 ABC 或漏写装饰器,子类就能绕过强制实现检查,运行时才在调用时抛 NotImplementedError —— 这会让问题延迟暴露。
更隐蔽的问题是:Python 的模板方法容易被误写成普通继承 + 方法覆盖,结果子类忘了调父类的 template_method(),或者自己重写了整个流程,导致骨架失效。建议在抽象基类里把模板方法设为 @final(Python 3.12+)或加注释警告。
示例片段:
from abc import ABC, abstractmethod
<p>class DataProcessor(ABC):
def run(self): # 模板方法,不允许子类重写
self.load()
self.transform()
self.save()</p><pre class='brush:java;toolbar:false;'>@abstractmethod
def load(self):
pass
@abstractmethod
def transform(self):
pass
def save(self): # hook,默认实现
print("saving to disk...")别让模板方法变成“配置地狱”
有人为了“灵活”,在模板方法里塞一堆 if-else 分支,靠参数控制走哪条子流程,再把分支逻辑拆成不同子类——这其实退化成了策略模式,还多了一层继承包袱。真需要运行时切换行为,直接用策略对象注入更轻量。
另一个高发问题是过度分层:把一个简单的三步操作拆成 prepareStep1()、doStep1()、verifyStep1() 三个 abstract 方法,结果每个子类都要写六行样板代码。判断标准很简单:如果两个子类中,某一步的实现几乎一样,那它就不该是 abstract 的,应该提到抽象类里作为默认实现。
真正难的不是写对模板方法,而是判断哪些逻辑值得“冻结流程”,哪些该交给组合或配置。这个边界,往往要等到第二个、第三个子类出现时才看得清。








