当前位置: 首页 > article >正文

Golang学习笔记_40——模版方法模式

Golang学习笔记_37——外观模式
Golang学习笔记_38——享元模式
Golang学习笔记_39——策略模式


文章目录

    • 一、核心概念
      • 1. 定义
      • 2. 解决的问题
      • 3. 核心角色
      • 4. 类图
    • 二、特点分析
    • 三、适用场景
      • 1. 文件解析系统
      • 2. 设备初始化流程
      • 3. OTP验证系统
    • 四、Go语言实现示例
      • 输出结果
    • 五、高级应用
      • 1. 钩子方法扩展
      • 2. 组合模板方法
    • 六、与其他模式对比
    • 七、总结
      • 设计要点
      • Go语言实现建议


一、核心概念

1. 定义

模板方法模式是一种行为型设计模式,通过在抽象类中定义算法的骨架,并将部分步骤的实现延迟到子类中,实现代码复用和扩展控制。其核心特点包括:

  • 算法框架固化:父类定义不可变的执行流程
  • 步骤差异化:允许子类重写特定步骤实现
  • 扩展控制:通过钩子方法提供选择性扩展点

2. 解决的问题

  • 重复代码:多个类有相同算法流程但部分步骤不同
  • 流程控制:需要确保算法执行顺序的稳定性
  • 扩展约束:希望控制子类对父类方法的修改范围

3. 核心角色

角色作用
AbstractClass定义模板方法(算法骨架)和基本方法(抽象/具体/钩子方法)
ConcreteClass实现抽象类中的抽象方法,完成具体步骤
Client调用模板方法执行算法

4. 类图

模版方法模式类图

@startuml
abstract class AbstractClass {
    + templateMethod()
    + {abstract} primitiveStep1()
    + {abstract} primitiveStep2()
    + hookMethod()
}

class ConcreteClass {
    + primitiveStep1()
    + primitiveStep2()
    + hookMethod()
}

AbstractClass <|-- ConcreteClass
@enduml

二、特点分析

优点

  1. 代码复用:将公共代码提升到抽象类(网页3指出可减少30%重复代码)
  2. 流程控制:父类控制算法结构,避免子类破坏流程(网页4强调模板方法常用final修饰)
  3. 扩展可控:通过钩子方法提供有限扩展点(网页5提到可增加算法灵活性)

缺点

  1. 继承限制:Go语言需通过组合模拟(网页9显示需使用接口+结构体组合)
  2. 类膨胀:每个算法变体需单独子类(网页7指出会增加类数量)
  3. 理解成本:需区分模板方法、基本方法和钩子方法

三、适用场景

1. 文件解析系统

// 抽象类
type FileParser interface {
    Parse() // 模板方法
    OpenFile()
    ExtractData()
    CloseFile()
    FormatReport() // 钩子方法
}

// PDF解析(网页4案例)
type PDFParser struct {
    FileParser
}

func (p *PDFParser) OpenFile() {
    fmt.Println("解析PDF文件头")
}

func (p *PDFParser) ExtractData() {
    fmt.Println("提取PDF文本内容")
}

2. 设备初始化流程

type DeviceInitializer interface {
    Initialize()
    powerOn()
    loadDriver()
    checkStatus() bool // 钩子方法
}

// 摄像头初始化
type CameraInitializer struct{}

func (c *CameraInitializer) powerOn() {
    fmt.Println("启动摄像头电源")
}

func (c *CameraInitializer) checkStatus() bool {
    return true // 实现状态检查
}

3. OTP验证系统

type OTPSender interface {
    SendOTP()
    generateCode()
    saveToCache()
    prepareMessage()
    send() // 抽象方法
}

// 短信OTP实现
type SMSOTP struct{}

func (s *SMSOTP) send() {
    fmt.Println("通过短信发送验证码")
}

四、Go语言实现示例

示例类图

package template_method_demo

import "fmt"

// AccountOpeningHandler 抽象接口定义开户流程
type AccountOpeningHandler interface {
	VerifyIdentity()      // 身份验证
	CreditAssessment()    // 信用评估
	SignAgreement()       // 签订协议
	OpenAccount()         // 开户
	SendNotification()    // 发送消息
	NeedFaceToFace() bool // 是否需要面签
}

// AccountOpeningHandlerTemplate 模版方法控制器
type AccountOpeningHandlerTemplate struct {
	handler AccountOpeningHandler
}

// Execute 执行开户流程(模版方法)
func (t *AccountOpeningHandlerTemplate) Execute() {
	fmt.Println("执行开户流程")
	if t.handler.NeedFaceToFace() {
		fmt.Println("需要面签")

	}
	t.handler.VerifyIdentity()

	// 信用评估
	t.handler.CreditAssessment()

	// 签订协议
	fmt.Println("[通用步骤] 生成标准协议模板")
	t.handler.SignAgreement()

	// 开户
	fmt.Println("[通用步骤] 连接央行征信系统")
	t.handler.OpenAccount()

	// 发送消息
	t.handler.SendNotification()

	fmt.Println("=== 流程结束 ===")
}

// NormalAccountHandler 普通个人账户实现
type NormalAccountHandler struct {
}

func (p *NormalAccountHandler) VerifyIdentity() {
	fmt.Println("普通账户:身份验证")
}

func (p *NormalAccountHandler) CreditAssessment() {
	fmt.Println("普通账户:信用评估")
}

func (p *NormalAccountHandler) SignAgreement() {
	fmt.Println("普通账户:签订协议")
}

func (p *NormalAccountHandler) OpenAccount() {
	fmt.Println("普通账户:开户")
}

func (p *NormalAccountHandler) SendNotification() {
	fmt.Println("普通账户:发送消息")
}

func (p *NormalAccountHandler) NeedFaceToFace() bool {
	return true
}

// 企业VIP账户实现
type VIPAccountHandler struct{}

func (p *VIPAccountHandler) VerifyIdentity() {
	fmt.Println("VIP账户:身份验证")
}

func (p *VIPAccountHandler) CreditAssessment() {
	fmt.Println("VIP账户:信用评估")
}

func (p *VIPAccountHandler) SignAgreement() {
	fmt.Println("VIP账户:签订协议")
}

func (p *VIPAccountHandler) OpenAccount() {
	fmt.Println("VIP账户:开户")
}

func (p *VIPAccountHandler) SendNotification() {
	fmt.Println("VIP账户:发送消息")
}

func (p *VIPAccountHandler) NeedFaceToFace() bool {
	return false
}

func test() {
	// 普通账户开户流程
	normalAccountHandler := &NormalAccountHandler{}
	normalAccountTemplate := &AccountOpeningHandlerTemplate{
		handler: normalAccountHandler,
	}
	normalAccountTemplate.Execute()

	// VIP账户开户流程
	vipAccountHandler := &VIPAccountHandler{}
	vipAccountTemplate := &AccountOpeningHandlerTemplate{
		handler: vipAccountHandler,
	}
	vipAccountTemplate.Execute()
}

输出结果

=== RUN   Test_test
执行开户流程
需要面签
普通账户:身份验证
普通账户:信用评估
[通用步骤] 生成标准协议模板
普通账户:签订协议
[通用步骤] 连接央行征信系统
普通账户:开户
普通账户:发送消息
=== 流程结束 ===
执行开户流程
VIP账户:身份验证
VIP账户:信用评估
[通用步骤] 生成标准协议模板
VIP账户:签订协议
[通用步骤] 连接央行征信系统
VIP账户:开户
VIP账户:发送消息
=== 流程结束 ===
--- PASS: Test_test (0.00s)
PASS

五、高级应用

1. 钩子方法扩展

type ReportGenerator interface {
    Generate()
    collectData()
    formatData()
    needChart() bool // 钩子方法
    addChart()
}

// PDF报告生成
type PDFReport struct{}

func (p *PDFReport) needChart() bool {
    return false // 关闭图表功能
}

2. 组合模板方法

type AdvancedCompressor struct {
    Compressor
    Encryptor // 组合加密策略
}

func (a *AdvancedCompressor) processData() {
    a.Compressor.processData()
    a.Encrypt() // 添加加密步骤
}

六、与其他模式对比

模式核心区别典型场景
策略模式通过组合切换完整算法(网页7对比)支付方式选择
工厂方法创建对象 vs 定义算法(网页4关联)对象创建过程
装饰器模式运行时动态扩展 vs 编译时确定功能叠加(如加密压缩)

七、总结

设计要点

  1. 抽象粒度:合理划分步骤粒度(建议5-8个步骤)
  2. 扩展控制:使用final限制模板方法,提供钩子扩展点
  3. 性能优化:避免在模板方法中进行复杂计算(网页10建议将耗时操作放在具体类)

Go语言实现建议

  1. 使用interface + struct组合替代继承
  2. 通过embedding实现方法复用
  3. 采用functional options模式实现钩子方法

http://www.kler.cn/a/570774.html

相关文章:

  • Tauri+React跨平台开发环境搭建全指南
  • IDEA 接入 Deepseek
  • 如何使用Docker一键本地化部署LibrePhotos搭建私有云相册
  • Android开发,多宫格列表实现
  • Java——通配符以及上下限
  • 人工智能AI在汽车设计领域的应用探索
  • CPU负载高告警问题的定位与优化建议
  • 【MySQL】使用LOAD DATA INFILE导入数据时报错:Errcode: 2 - No such file or directory
  • UnrealEngine UE5 可视化 从地球观察火星 金星 土星 运动轨迹
  • PyTorch 中实现模型训练看板实时监控训练过程中的关键指标
  • 【开发环境配置】基于Openssh的git多key配置
  • Magic 1-For-1: 在一分钟内生成一分钟视频片段(基于Python实现,视频生成模型)
  • 蓝桥杯C语言组:基于蓝桥杯煤球数目问题的数列累加解决方案研究
  • SQL调优
  • AI大模型之一 GodeGPT调用Dify+DeepSeek属于自己私域模型
  • Zabbix zbx_auditlog_global_script SQL注入漏洞缓解和修复方案
  • C++014(elif语句)
  • Highcharts 配置语法详解
  • Redis除了做缓存还能做什么?
  • 如何在Android中实现多线程