模板方法模式
约 617 字大约 2 分钟
2025-12-27
定义
定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
模板方法模式的优点
- 封装不变部分,扩展可变部分
- 提取公共部分代码,便于维护
- 行为由父类控制,子类实现
模板方法模式的缺点
按照一般设计习惯,抽象类负责声明最抽象、最一般的事物属性和方法,实现类完成具体的事物属性和方法。但是模板方法模式却颠倒了,抽象类定义了部分抽象方法,由子类实现,子类执行的结果影响了父类的结果,也就是子类对父类产生了影响,这在复杂的项目中,会带来代码阅读的难度。
模板方法模式的使用场景
- 多个子类有公有的方法,并且逻辑基本相同。
- 重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。
- 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为。
示例
// sort/sort.go 模板方法中的可变步骤
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
// sort/sort.go 模板方法(Template Method)
// 定义排序的固定流程,控制算法的整体执行
func Sort(data Interface) {
n := data.Len()
if n <= 1 {
return
}
limit := bits.Len(uint(n))
pdqsort(data, 0, n, limit)
}
// 用户自定义类型
type User struct {
Name string
Age int
}
// 可变步骤实现 1:按年龄排序
type ByAge []User
func (a ByAge) Len() int { return len(a) }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
// 可变步骤实现 2:按名字排序
type ByName []User
func (a ByName) Len() int { return len(a) }
func (a ByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
func (a ByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
// 运行时注入可变步骤(Hook),执行模板方法
func main() {
users := []User{
{"AAA", 30},
{"BBB", 20},
{"CCC", 10},
}
// 模板方法调用,按年龄排序
sort.Sort(ByAge(users))
fmt.Println(users)
// 模板方法调用,按名字排序
sort.Sort(ByName(users))
fmt.Println(users)
}