GoLang设计模式16|GoLang设计模式16 - 模板方法模式
模板方法设计模式是一种行为型设计模式。这种模式通过常用于为某种特定的操作定义一个模板或者算法模型。
以一次性密码(OTP:One Time Password)为例。我们常见的一次性密码有两种:短信密码(SMS OTP)或者邮件密码(Email OTP)。不过不管是短信密码还是邮件密码,它们的处理步骤都是一样的,步骤如下:
- 生成一串随机字符串
- 将字符串保存进缓存用来执行后续的验证
- 准备通知内容
- 发送通知
- 记录统计信息
在这类场景中,即一个操作的步骤是固定的,只是在具体的执行方式上存在差异,这时我们就可以用到模板方法模式了。在模板方法模式中,我们通常会为这个操作定义一个模板接口或算法模型接口,接口中包含固定方法,然后由具体的实现类来重写相关接口并实现这些操作。
下面是一次性密码这个例子的实现:
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所需的相关步骤 - 下面的
sms
和email
是iOtp
接口的实现 - 在结构体
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 metricsEMAIL: 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
【GoLang设计模式16|GoLang设计模式16 - 模板方法模式】END!!
推荐阅读
- opencv|opencv C++模板匹配的简单实现
- web网页模板|如此优秀的JS轮播图,写完老师都沉默了
- 设计模式-代理模式-Proxy
- 三门问题(蒙提霍尔悖论)分析与Golang模拟
- 通过复盘快速成长(附模板)
- 设计模式【15】--从审批流中学习责任链模式
- 2020-11-18迭代器设计模式
- golang锁竞争性能
- 设计模式(6)|设计模式(6) : 原型模式
- 8发布-订阅模式