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

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

  1. 生成一串随机字符串
  2. 将字符串保存进缓存用来执行后续的验证
  3. 准备通知内容
  4. 发送通知
  5. 记录统计信息

在以上的步骤中,除了第4项“发送通知”的具体方式不一样,其他步骤都是不变的。即使以后有了新的一次性密码发送方式,可以预见以上的步骤也是不变的。

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

下面是一次性密码这个例子的实现:

otp.go

type iOtp interface {
genRandomOTP(int) string
saveOTPCache(string)
getMessage(string) string
sendNotification(string) error
publishMetric()
} 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.publishMetric()
return nil
}

简单解读下这段代码:

  • 在上面的代码中定义了iOtp接口,这个接口中的方法即OTP所需的相关步骤
  • 下面的smsemailiOtp接口的实现
  • 在结构体otp中定义了模板方法genAndSendOTP()

此外注意下:在上面这段代码中将iOtp接口和结构体otp合在了一起,提供了类似于抽象类的实现,这种做法大家需要的时候可以借鉴下。

sms.go

import "fmt"

type sms struct {
otp
} func (s *sms) genRandomOTP(len int) string {
randomOTP := "1234"
fmt.Printf("SMS: generating random otp %s\n", randomOTP)
return randomOTP
} func (s *sms) saveOTPCache(otp string) {
fmt.Printf("SMS: saving otp: %s to cache\n", otp)
} func (s *sms) getMessage(otp string) string {
return "SMS OTP for login is " + otp
} func (s *sms) sendNotification(message string) error {
fmt.Printf("SMS: sending sms: %s\n", message)
return nil
} func (s *sms) publishMetric() {
fmt.Printf("SMS: publishing metrics\n")
}

email.go

import "fmt"

type email struct {
otp
} func (s *email) genRandomOTP(len int) string {
randomOTP := "1234"
fmt.Printf("EMAIL: generating random otp %s\n", randomOTP)
return randomOTP
} func (s *email) saveOTPCache(otp string) {
fmt.Printf("EMAIL: saving otp: %s to cache\n", otp)
} func (s *email) getMessage(otp string) string {
return "EMAIL OTP for login is " + otp
} func (s *email) sendNotification(message string) error {
fmt.Printf("EMAIL: sending email: %s\n", message)
return nil
} func (s *email) publishMetric() {
fmt.Printf("EMAIL: publishing metrics\n")
}

main.go

import "fmt"

func main() {
smsOTP := &sms{}
o := otp{
iOtp: smsOTP,
}
o.genAndSendOTP(4)
fmt.Println("")
emailOTP := &email{}
o = otp{
iOtp: emailOTP,
}
o.genAndSendOTP(4)
}

输出内容为:

SMS: generating random otp 1234
SMS: saving otp: 1234 to cache
SMS: sending sms: SMS OTP for login is 1234
SMS: publishing metrics EMAIL: generating random otp 1234
EMAIL: saving otp: 1234 to cache
EMAIL: sending email: EMAIL OTP for login is 1234
EMAIL: publishing metrics

代码已上传至GitHub: zhyea / go-patterns / template-method-pattern

END!!

最新文章

  1. Java Switch(String)
  2. 【Oracle 数据迁移】环境oracle 11gR2,exp无法导出空表的表结构【转载】
  3. 【NOIP2010】【P1317】乌龟棋
  4. jsoi2015 R2——滚粗记
  5. Mina入门:mina版之HelloWorld
  6. layer初步使用
  7. drawpoly()函数的用法
  8. fast ai-lesson 1 报错解决方法(正则表达式提取文件名)
  9. .net core使用EasyNetQ做EventBus
  10. java和js中int和String相互转换常用方法整理
  11. MonkeyRunner测试工具小结
  12. XX-NET史上最详细完整教程
  13. ajax请求本地文件
  14. Django框架----Form组件补充
  15. day 67 django 之ORM 基础安装
  16. Java程序---多数字求和
  17. JFinal Web开发学习(八)后台集成H-ui-admin前端框架
  18. Expo大作战(五)--expo中app.json 文件的配置信息
  19. java基础思维导图,让java不再难懂
  20. java中package import区别

热门文章

  1. 洛谷2375 NOI2014动物园(KMP)
  2. BG的本性
  3. 2020.10.16--vj个人赛补题
  4. NX屏蔽窗口的按钮
  5. spark 解决错误java.io.InvalidClassException
  6. 【UE4 C++】获取运行时间、设置时间流速、暂停游戏
  7. djago后台管理页面
  8. 提升使用Linux效率的小操作
  9. BOOST内存管理-intrusive_ptr
  10. 一张图彻底搞懂Spring循环依赖