设计模式-模版方法模式

140 阅读2分钟

模板方法设计模式是一种行为型设计模式。这种模式通过常用于为某种特定的操作定义一个模板或者算法模型。

以一次性密码(OTP:One Time Password)为例。我们常见的一次性密码有两种:短信密码(SMS OTP)或者邮件密码(Email OTP)。不过不管是短信密码还是邮件密码,它们的处理步骤都是一样的,步骤如下:

1、生成一串随机字符串
2、将字符串保存进缓存用来执行后续的验证
3、准备通知内容
4、发送通知
5、记录统计信息
在以上的步骤中,除了第4项“发送通知”的具体方式不一样,其他步骤都是不变的。即使以后有了新的一次性密码发送方式,可以预见以上的步骤也是不变的。

在这类场景中,即一个操作的步骤是固定的,只是在具体的执行方式上存在差异,这时我们就可以用到模板方法模式了。在模板方法模式中,我们通常会为这个操作定义一个模板接口或算法模型接口,接口中包含固定方法,然后由具体的实现类来重写相关接口并实现这些操作。

Go

// OTP所需的相关步骤
type iOtp interface {
    genRandomOTP(int) string
    saveOTPCache(string)
    getMessage(string) string
    sendNotification(string) error
    publishMetric()
}

type otp struct {
    iOtp iOtp
}

// 模板方法
func (i *otp) genAndSendOTP(otpLength int) error {

    otp := i.iOtp.genRandomOTP(otpLength)

    i.iOtp.saveOTPCache(otp)

    msg := i.iOtp.getMessage(otp)

    err := i.iOtp.sendNotification(msg)
    if err != nil {
            return err
    }
    i.iOtp.publishMetric()

    return nil
}

// -------------SMS------------------
type sms struct {
	otp
}

func (s *sms) genRandomOTP(otpLength int) string {
    msg := fmt.Sprintf("生成的消息%d", otpLength)
    return msg
}

func (s *sms) saveOTPCache(msg string) {
    fmt.Printf("消息已经保存%s\n", msg)
}

func (s *sms) getMessage(msg string) string {
    fmt.Printf("获取消息成功%s\n", msg)
    return msg
}

func (s *sms) sendNotification(msg string) error {
    fmt.Printf("发送消息调用%s\n", msg)
    if msg == "aaa" {
            return errors.New("错误")
    }
    return nil
}
func (s *sms) publishMetric() {
    fmt.Println("统计信息成功")
}

func main() {
    o := otp{
        iOtp: &sms{},
    }
    o.genAndSendOTP(4)
}

TS

interface iOtp {
    genRandomOTP(num: number): string
    saveOTPCache(msg: string): void
    getMessage(): string
    sendNotification(): string
    publishMetric(): void
}

// 模版
class Sms implements iOtp {
  msg: string

  constructor() {
    this.msg = ''
  }
  genRandomOTP(num: number) {
    console.log(`生成信息${num}`)
    return "生成信息" + num
  
  }
  saveOTPCache(msg: string): void {
    console.log(`保存成功${msg}`)
    this.msg = msg
  }
  getMessage() {
    console.log(`获取成功${this.msg}`)
    return this.msg
  }
  sendNotification() {
    console.log(`发送消息成功${this.msg}`)
    if (this.msg) {
      console.log(`发送消息成功${this.msg}`)
      return ''
    } else {
      return '发送失败'
    }
  }
  publishMetric(): void {
    console.log('统计信息成功')
  }
}

class Otp extends Sms {
  num: number
  constructor(num: number) {
    super()
    this.num = num
  }
  genAndSendOTP() {
    const msg = this.genRandomOTP(this.num)
    this.saveOTPCache(msg)
    this.getMessage()
    this.sendNotification()
    this.publishMetric()
  }
}
function main() {
  let sms1 = new Otp(111)
  sms1.genAndSendOTP()
  let sms2 = new Otp(333)
  sms2.genAndSendOTP()
}