跳到主要内容

模板方法模式

简介

模板方法模式(Template Method Pattern)可以在基类中定义一个算法的框架,允许子类在不修改框架结构的情况下重写算法的特定步骤。

角色组成:

  • 抽象类(Abstract Class):声明作为算法步骤的方法,以及依次调用它们的实际模板方法。
  • 具体类(Concret Class):可以重写所有步骤,但不能重写模板方法自身。

使用场景

  • 框架扩展点设计
  • 多步骤流程标准化
  • 算法流程复用
  • 生命周期控制
  • 代码复用与规范约束

优点

  • 提高代码复用性(公共流程在父类实现)
  • 约束子类行为(强制实现关键步骤)
  • 符合开闭原则(扩展子类而非修改父类)
  • 提供清晰的扩展点(钩子方法)

缺点

  • 子类数量可能过多(每个差异需一个子类)
  • 父类定义流程,子类灵活性受限
  • 继承强耦合(子类依赖父类实现细节)
  • 复杂流程可能导致模板方法难以维护

示例代码

Simple

实现一次性密码功能,将一次性密码发送给用户的方式有多种,如短信、邮件,但无论哪种方式,流程都是相同的:

  1. 生成随机n位数字
  2. 在缓存中存储这组数字,以便验证
  3. 准备工作
  4. 发送通知
  5. 发布
package templatemethod

import (
"fmt"
"math"
"math/rand"
)

type IOtp interface {
GenRandomOTP(int) int
SaveOTPCache(int)
GetMessage(int) string
SendNotification(string) error
Publish()
}

type Otp struct {
IOtp IOtp
}

func (o *Otp) GenAndSendOTP(otpLength int) error {
otp := o.IOtp.GenRandomOTP(otpLength)
o.IOtp.SaveOTPCache(otp)
message := o.IOtp.GetMessage(otp)
err := o.IOtp.SendNotification(message)
if err != nil {
return err
}
o.IOtp.Publish()
return nil
}

type Sms struct {
Otp
}

func (s *Sms) GenRandomOTP(length int) int {
// rand.Seed(time.Now().UnixNano())
min := int(math.Pow10(length - 1))
max := int(math.Pow10(length)) - 1
return rand.Intn(max-min+1) + min
}

func (s *Sms) SaveOTPCache(otp int) {
fmt.Printf("Saving otp %d to cache\n", otp)
}

func (s *Sms) GetMessage(otp int) string {
return fmt.Sprintf("Your OTP is %d", otp)
}

func (s *Sms) SendNotification(message string) error {
fmt.Printf("Sending sms: %s\n", message)
return nil
}

func (s *Sms) Publish() {
fmt.Println("Publishing message as SMS")
}

客户端

package templatemethod

import "testing"

func TestTemplateMethod(t *testing.T) {
sms := &Sms{}
o := Otp{sms}
err := o.GenAndSendOTP(6)
if err != nil {
t.Errorf("Error sending OTP: %v\n", err)
}
}