关于 gof-template-method
讲解模板方法模式的设计模式技能,帮助开发者处理流程顺序固定、部分步骤由子类调整的算法。内容涵盖适用条件、步骤类型与常见误用。
主要功能
- 01共享算法骨架
- 02具体、抽象与钩子步骤
- 03子类覆写的选择指导
- 04反模式与相关模式
适用场景
- 01建模阶段各异的工作流
- 02构建框架生命周期钩子
- 03比较模板方法与策略模式
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ yonatankarp/ software-design-skills --skill gof-template-method安装后在 Claude Code 中输入/gof-template-method确认已加载。
详细介绍
一句话概述
在基类方法中定义算法的骨架,将部分步骤延迟到子类实现,让子类在不改变算法结构的情况下重新定义特定步骤。
何时使用此技能
- 两个或更多类遵循相同的整体流程,但有一两个步骤不同(Beck 的“咖啡和茶都要冲泡”示例)。
- 工作流的顺序固定,但具体阶段会因使用场景而异(例如,解析流水线中,分词步骤因格式而异)。
- 跨领域的框架钩子:基类提供生命周期方法,子类重写所需的方法(Spring 的
JdbcTemplate、JUnit 的setUp/tearDown)。
何时不使用此技能
- 变化的是算法本身,而不是骨架中的步骤——此时应使用
gof-strategy。 - 只有一个步骤会变化,且变化很小——使用函数参数或 lambda 比创建子类更简单。
- 基类成了继承的瓶颈,导致子类无法执行模板之外的操作——这表明抽象过于僵化。
核心内容
TemplateMethod 是基类上的一个方法(通常为 final 或不可重写),它会按顺序调用一系列步骤,其中一些在基类中实现,另一些则是抽象方法或由子类重写的“钩子”方法。
base.run():
step1() # final, implemented in base
step2Abstract() # abstract — subclass must provide
step3Hook() # default no-op — subclass may override
step4() # final, implemented in base
三种步骤:
- 具体步骤——在基类中完整实现。
- 抽象步骤——必须由子类实现。
- 钩子步骤——提供默认行为(通常为空操作或合理的默认值);子类可以重写。
“好莱坞原则”——“别打电话给我们,我们会打给你”——是这一模式在框架层面的体现。基类会在适当时机调用子类的重写方法;子类不会通过调用基类来驱动工作流。
决策启发
- 在骨架相同、步骤不同的情况下使用。如果只有一个步骤不同,可以考虑使用函数参数而不是子类。
- 将模板方法设为
final(或不可重写),以免子类破坏工作流。 - 区分抽象步骤(必须重写)和钩子步骤(可以重写),并说明各自的类型。
- 如果子类不断需要重写越来越多的步骤才能完成复杂工作,说明模板过于僵化。
反模式
- 模板方法中的“模板”是一个包含许多可重写步骤的巨型方法——模板方法的优势在于其约束性,而这种约束性此时已荡然无存。
- 在子类中重写模板方法本身——这违背了该模式的目的。
- 在子类重写的步骤中调用
super.step1()——这会让子类依赖基类的内部实现。
另请参阅
gof-strategy——当变化的是整个算法,而不只是算法中的步骤时使用。gof-factory——工厂方法本身就是模板方法的一种实例(算法将具体类型的选择交由子类决定)。gof-kotlin-idioms——Kotlin 中open/final的默认行为使模板方法更加明确;对于一两个变化步骤,高阶函数通常比基于子类的模板更合适。
参考资料
- Head First Design Patterns(第 2 版),第 8 章(“封装算法:模板方法模式”)——以咖啡和茶的示例对该模式进行了经典阐述。
评论
支持 Markdown