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