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
二、特点分析
优点
- 代码复用:将公共代码提升到抽象类(网页3指出可减少30%重复代码)
- 流程控制:父类控制算法结构,避免子类破坏流程(网页4强调模板方法常用final修饰)
- 扩展可控:通过钩子方法提供有限扩展点(网页5提到可增加算法灵活性)
缺点
- 继承限制:Go语言需通过组合模拟(网页9显示需使用接口+结构体组合)
- 类膨胀:每个算法变体需单独子类(网页7指出会增加类数量)
- 理解成本:需区分模板方法、基本方法和钩子方法
三、适用场景
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 编译时确定 | 功能叠加(如加密压缩) |
七、总结
设计要点
- 抽象粒度:合理划分步骤粒度(建议5-8个步骤)
- 扩展控制:使用final限制模板方法,提供钩子扩展点
- 性能优化:避免在模板方法中进行复杂计算(网页10建议将耗时操作放在具体类)
Go语言实现建议
- 使用
interface
+struct
组合替代继承 - 通过
embedding
实现方法复用 - 采用
functional options
模式实现钩子方法