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

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


文章目录


一、核心概念

1. 定义

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

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

2. 解决的问题

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

3. 核心角色

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

4. 类图

plantuml 复制代码
@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. 文件解析系统

go 复制代码
// 抽象类
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. 设备初始化流程

go 复制代码
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验证系统

go 复制代码
type OTPSender interface {
    SendOTP()
    generateCode()
    saveToCache()
    prepareMessage()
    send() // 抽象方法
}

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

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

四、Go语言实现示例

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()
}

输出结果

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

五、高级应用

1. 钩子方法扩展

go 复制代码
type ReportGenerator interface {
    Generate()
    collectData()
    formatData()
    needChart() bool // 钩子方法
    addChart()
}

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

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

2. 组合模板方法

go 复制代码
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模式实现钩子方法
相关推荐
齐尹秦2 分钟前
HTML5 Web Workers 学习笔记
笔记·学习
云徒川3 分钟前
【设计模式】过滤器模式
windows·python·设计模式
DarkBule_9 分钟前
零基础驯服GitHub Pages
css·学习·html·github·html5·web
烧瓶里的西瓜皮35 分钟前
Go语言从零构建SQL数据库引擎(2)
数据库·sql·golang
余多多_zZ1 小时前
鸿蒙学习手册(HarmonyOSNext_API16)_应用开发UI设计:Swiper
学习·ui·华为·harmonyos·鸿蒙系统
淬渊阁1 小时前
汇编学习之《扩展指令指针寄存器》
汇编·学习
lalapanda1 小时前
UE5学习记录part12
学习·ue5
不要影响我叠Q2 小时前
《Fundamentals of Electromigration-Aware IntegratedCircuit Design》笔记
笔记
蒹葭苍苍8732 小时前
LoRA、QLoRA微调与Lama Factory
人工智能·笔记
并不会2 小时前
多线程案例-单例模式
java·学习·单例模式·单线程·多线程·重要知识