16. 模板方法模式(Template Method)

问题:多个流程有相同的骨架,只有个别步骤不同。

核心:父类定义算法骨架,子类实现具体步骤。

type UserRecord = { name: string; age: number };

abstract class DataParser<T> {
  parse(): void {
    const raw = this.read();
    const data = this.process(raw);
    this.output(data);
  }
  protected abstract read(): string;
  protected abstract process(raw: string): T;
  protected output(data: T): void { console.log(`结果: ${JSON.stringify(data)}`); }
}

class JSONParser extends DataParser<UserRecord> {
  protected read(): string { return '{"name":"小明","age":25}'; }
  protected process(raw: string): UserRecord { return JSON.parse(raw) as UserRecord; }
}

class CSVParser extends DataParser<UserRecord> {
  protected read(): string { return '小明,25'; }
  protected process(raw: string): UserRecord {
    const [name, age] = raw.split(',');
    return { name, age: Number(age) };
  }
}

new JSONParser().parse(); // 结果: {"name":"小明","age":25}
new CSVParser().parse();  // 结果: {"name":"小明","age":25}
package template

import (
  "encoding/json"
  "fmt"
  "strings"
)

type DataParser interface {
  Read() string
  Process(raw string) any
}

func Parse(p DataParser) {
  raw := p.Read()
  data := p.Process(raw)
  fmt.Printf("结果: %v\n", data)
}

type JSONParser struct{}

func (j JSONParser) Read() string {
  return `{"name":"小明","age":25}`
}

func (j JSONParser) Process(raw string) any {
  var result map[string]any
  json.Unmarshal([]byte(raw), &result)
  return result
}

type CSVParser struct{}

func (c CSVParser) Read() string { return "小明,25" }

func (c CSVParser) Process(raw string) any {
  parts := strings.Split(raw, ",")
  return map[string]any{"name": parts[0], "age": parts[1]}
}

实战场景

  • 数据导入流程:读取文件、解析数据、校验字段、写入数据库、生成报告是固定骨架,不同文件类型只改解析步骤。
  • 支付流程:创建订单、调用渠道、校验回调、更新状态、通知用户固定,渠道差异放到子步骤。
  • 构建流程:安装依赖、编译、测试、打包、发布是骨架,不同项目重写其中某些步骤。
  • 页面渲染流程:加载数据、鉴权、构造 props、渲染模板固定,不同页面实现自己的数据和模板。
  • 爬虫任务:请求页面、解析内容、去重、存储、限速固定,不同站点只实现 URL 和解析逻辑。
  • 机器学习训练:加载数据、预处理、训练、评估、保存模型固定,不同模型替换其中几步。
  • 报表生成:查询数据、聚合、套模板、导出、发送固定,不同报表重写查询和模板。
  • 表单提交:收集数据、校验、转换、提交、处理错误固定,不同表单提供字段和规则。
  • 游戏关卡加载:加载资源、初始化角色、设置地图、注册事件固定,不同关卡只替换配置和脚本。
  • CLI 命令执行:解析参数、校验环境、执行核心动作、输出结果固定,不同命令只重写核心动作。