模板方法设计模式是一种行为型设计模式。这种模式通过常用于为某种特定的操作定义一个模板或者算法模型。
以一次性密码(OTP:One Time Password)为例。我们常见的一次性密码有两种:短信密码(SMS OTP)或者邮件密码(Email OTP)。不过不管是短信密码还是邮件密码,它们的处理步骤都是一样的,步骤如下:
- 生成一串随机字符串
- 将字符串保存进缓存用来执行后续的验证
- 准备通知内容
- 发送通知
- 记录统计信息
在以上的步骤中,除了第4项“发送通知”的具体方式不一样,其他步骤都是不变的。即使以后有了新的一次性密码发送方式,可以预见以上的步骤也是不变的。
在这类场景中,即一个操作的步骤是固定的,只是在具体的执行方式上存在差异,这时我们就可以用到模板方法模式了。在模板方法模式中,我们通常会为这个操作定义一个模板接口或算法模型接口,接口中包含固定方法,然后由具体的实现类来重写相关接口并实现这些操作。
下面是一次性密码这个例子的实现:
1 type iOtp interface { 2 genRandomOTP(int) string 3 saveOTPCache(string) 4 getMessage(string) string 5 sendNotification(string) error 6 publishMetric() 7 } 8 9 type otp struct { 10 iOtp iOtp 11 } 12 13 func (o *otp) genAndSendOTP(otpLength int) error { 14 otp := o.iOtp.genRandomOTP(otpLength) 15 o.iOtp.saveOTPCache(otp) 16 message := o.iOtp.getMessage(otp) 17 err := o.iOtp.sendNotification(message) 18 if err != nil { 19 return err 20 } 21 o.iOtp.publishMetric() 22 return nil 23 }
简单解读下这段代码:
iOtpsmsemailiOtpotpgenAndSendOTP()
iOtpotp
1 import "fmt" 2 3 type sms struct { 4 otp 5 } 6 7 func (s *sms) genRandomOTP(len int) string { 8 randomOTP := "1234" 9 fmt.Printf("SMS: generating random otp %s\n", randomOTP) 10 return randomOTP 11 } 12 13 func (s *sms) saveOTPCache(otp string) { 14 fmt.Printf("SMS: saving otp: %s to cache\n", otp) 15 } 16 17 func (s *sms) getMessage(otp string) string { 18 return "SMS OTP for login is " + otp 19 } 20 21 func (s *sms) sendNotification(message string) error { 22 fmt.Printf("SMS: sending sms: %s\n", message) 23 return nil 24 } 25 26 func (s *sms) publishMetric() { 27 fmt.Printf("SMS: publishing metrics\n") 28 } 29 30 type email struct { 31 otp 32 } 33 34 func (s *email) genRandomOTP(len int) string { 35 randomOTP := "1234" 36 fmt.Printf("EMAIL: generating random otp %s\n", randomOTP) 37 return randomOTP 38 } 39 40 func (s *email) saveOTPCache(otp string) { 41 fmt.Printf("EMAIL: saving otp: %s to cache\n", otp) 42 } 43 44 func (s *email) getMessage(otp string) string { 45 return "EMAIL OTP for login is " + otp 46 } 47 48 func (s *email) sendNotification(message string) error { 49 fmt.Printf("EMAIL: sending email: %s\n", message) 50 return nil 51 } 52 53 func (s *email) publishMetric() { 54 fmt.Printf("EMAIL: publishing metrics\n") 55 } 56 57 func main() { 58 smsOTP := &sms{} 59 o := otp{ 60 iOtp: smsOTP, 61 } 62 o.genAndSendOTP(4) 63 fmt.Println("") 64 emailOTP := &email{} 65 o = otp{ 66 iOtp: emailOTP, 67 } 68 o.genAndSendOTP(4) 69 }
输出内容为:
SMS: generating random otp 1234SMS: saving otp: 1234 to cacheSMS: sending sms: SMS OTP forlogin is 1234SMS: publishing metricsEMAIL: generating random otp 1234EMAIL: saving otp: 1234 to cacheEMAIL: sending email: EMAIL OTP forlogin is 1234EMAIL: publishing metrics