模板方法设计模式是一种行为型设计模式。这种模式通过常用于为某种特定的操作定义一个模板或者算法模型。
以一次性密码(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