模板方法模式的核心思想是定义一个操作的算法骨架,而将一些步骤延迟到子类中实现,使得子类可以不改变算法结构即可重定义该算法的某些特定步骤。Golang没有传统的类继承机制,但是可以通过接口定义流程框架,结构体组合实现步骤定制,同样可以完成模板方法模式的实现。

模板方法模式的核心结构
在Golang中实现模板方法模式,通常需要以下几个部分:
- 抽象接口(流程定义):定义整个流程的框架方法,以及需要子类实现的抽象步骤方法
- 具体实现结构体:实现抽象接口中定义的步骤方法,完成具体业务逻辑
- 模板调用方法:在抽象接口的实现中,按顺序调用各个步骤,形成固定流程
实现示例:数据导出流程
我们以数据导出流程为例,整个流程固定为:读取数据、处理数据、导出数据,其中读取数据和导出数据的逻辑会根据不同导出类型有所区别,处理数据的逻辑是通用的,符合模板方法模式的使用场景。
1. 定义抽象流程接口
首先定义DataExporter接口,包含流程框架方法和需要定制的步骤方法:
// 定义数据导出抽象接口,包含模板方法和抽象步骤
type DataExporter interface {
// 模板方法,定义固定流程
Export()
// 抽象步骤:读取数据,由具体实现结构体完成
readData() string
// 抽象步骤:导出数据,由具体实现结构体完成
outputData(data string)
// 通用步骤:处理数据,默认实现
processData(raw string) string
}
2. 实现基础模板结构体
定义一个基础结构体BaseExporter,实现通用的流程框架和通用步骤,具体的读取和导出步骤留空由子类实现:
// 基础导出结构体,实现通用逻辑
type BaseExporter struct {
// 嵌入接口,方便调用具体实现的方法
impl DataExporter
}
// 模板方法,定义固定流程:读取-处理-导出
func (b *BaseExporter) Export() {
// 调用具体实现的读取数据方法
rawData := b.impl.readData()
// 调用通用的数据处理方法
processedData := b.impl.processData(rawData)
// 调用具体实现的导出数据方法
b.impl.outputData(processedData)
}
// 通用数据处理逻辑,默认实现
func (b *BaseExporter) processData(raw string) string {
// 模拟通用处理:添加处理标记
return "[Processed]" + raw
}
// 基础结构体不实现readData和outputData,由具体实现结构体完成
3. 实现具体导出结构体
分别实现CSV导出和JSON导出两个具体结构体,定制读取和导出步骤:
// CSV导出实现
type CSVExporter struct {
BaseExporter
}
// 初始化CSV导出器,绑定自身到impl字段
func NewCSVExporter() *CSVExporter {
exporter := &CSVExporter{}
exporter.impl = exporter
return exporter
}
// 实现读取数据步骤
func (c *CSVExporter) readData() string {
return "id,name,age"
}
// 实现导出数据步骤
func (c *CSVExporter) outputData(data string) {
fmt.Println("导出CSV数据:" + data)
}
// JSON导出实现
type JSONExporter struct {
BaseExporter
}
// 初始化JSON导出器,绑定自身到impl字段
func NewJSONExporter() *JSONExporter {
exporter := &JSONExporter{}
exporter.impl = exporter
return exporter
}
// 实现读取数据步骤
func (j *JSONExporter) readData() string {
return `{"id":1,"name":"test"}`
}
// 实现导出数据步骤
func (j *JSONExporter) outputData(data string) {
fmt.Println("导出JSON数据:" + data)
}
4. 调用示例
以下是完整的调用代码,可以看到只需要调用Export方法,就会按照固定流程执行,同时自动使用具体结构体的定制步骤:
package main
import "fmt"
// 这里放入上面定义的接口和结构体代码
func main() {
// 创建CSV导出器并执行导出
csvExporter := NewCSVExporter()
csvExporter.Export()
// 创建JSON导出器并执行导出
jsonExporter := NewJSONExporter()
jsonExporter.Export()
}
运行上述代码,输出结果如下:
导出CSV数据:[Processed]id,name,age
导出JSON数据:[Processed]{"id":1,"name":"test"}
流程控制要点
在Golang中实现模板方法模式的流程控制需要注意以下几点:
- 模板方法(本例中的
Export)必须定义在基础结构体中,并且按顺序调用各个步骤,保证流程固定 - 具体实现结构体需要通过
impl字段绑定自身,这样基础结构体调用步骤时才能正确路由到具体实现的方法 - 通用步骤可以直接在基础结构体中实现,不需要具体结构体重复编写,实现代码复用
- 如果需要修改流程顺序,只需要修改基础结构体中的模板方法即可,所有具体实现都会同步生效
适用场景
该实现方式适合以下场景:
- 多个功能有固定且相同的流程框架,只有部分步骤逻辑不同
- 需要复用通用流程逻辑,避免重复编写相同代码
- 后续可能新增同类型的不同实现,需要保持流程统一
通过接口和结构体组合的方式,Golang可以很优雅地实现模板方法模式,既保留了模式的优势,又符合Golang的语言设计理念。