mcpField
G
gof-template-method

gof-template-method

github.com/yonatankarp开发143 次安装23 周前更新
代码仓库

关于 gof-template-method

讲解模板方法模式的设计模式技能,帮助开发者处理流程顺序固定、部分步骤由子类调整的算法。内容涵盖适用条件、步骤类型与常见误用。

主要功能

  1. 01共享算法骨架
  2. 02具体、抽象与钩子步骤
  3. 03子类覆写的选择指导
  4. 04反模式与相关模式

适用场景

  1. 01建模阶段各异的工作流
  2. 02构建框架生命周期钩子
  3. 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