zoukankan      html  css  js  c++  java
  • GoLang设计模式16 模板方法模式

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

    以一次性密码(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!!


    仅是学习笔记,难免出错,望不吝指点
  • 相关阅读:
    fatal: unable to access ‘https://github.com/Homebrew/brew/‘: Error in the HTTP2 framing layer
    leetcode题目两数和、最大字符串长度、中位数、最长回文子串
    zabbix5.x版本添加自定义监控+263邮件报警
    php过滤特殊字符方法
    js中e相关位置
    少有人走的路-心智成熟的旅程-斯科特·派克
    ios脱壳
    docker 容器开机自启
    Java8 Stream的使用
    Entity Frameworker 的核心 EDM(Entity Data Model)模式
  • 原文地址:https://www.cnblogs.com/amunote/p/15586554.html
Copyright © 2011-2022 走看看