[go] 模版方法模式

简介: [go] 模版方法模式

模版方法模式


在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中。模版方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。


模型说明



  • AbstractClass: 会声明作为算法步骤的方法, 以及依次调用它们的实际模板方法。 算法步骤可以被声明为抽象类型, 也可以提供一些默认实现。
  • ConcreteClass: 可以重写所有步骤, 但不能重写模板方法自身。


优缺点


1.优点

  • 你可仅允许客户端重写一个大型算法中的特定部分, 使得算法其他部分修改对其所造成的影响减小。
  • 你可将重复代码提取到一个超类中。


2.缺点


  • 部分客户端可能会受到算法框架的限制。
  • 通过子类抑制默认步骤实现可能会导致违反里氏替换原则
  • 模板方法中的步骤越多, 其维护工作就可能会越困难。


使用场景


  • 当你只希望客户端扩展某个特定算法步骤, 而不是整个算法或其结构时, 可使用模板方法模式。
  • 当多个类的算法除一些细微不同之外几乎完全一样时, 你可使用该模式。 但其后果就是, 只要算法发生变化, 你就可能需要修改所有的类。


参考代码


比如说我们需要给用户发送验证码,通过 sms、email 的方式。其具体的流程都是相同的:

  1. 生成随机的 n 位数字。
  2. 在缓存中保存这组数字以便进行后续验证。
  3. 准备内容。
  4. 发送通知。


// otp.go 模板方法
package main
type IOtp interface {
 genRandomOTP(int) string
 saveOTPCache(string)
 getMessage(string) string
 sendNotification(string) error
}
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
 }
 return nil
}
// sms.go 具体实现类
package main
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
}
// email.go 具体实现类
package main
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
}
// main.go 客户端
package main
import "fmt"
func main() {
 smsOTP := &Sms{}
 o := Otp{
  iOtp: smsOTP,
 }
 o.genAndSendOTP(4)
 fmt.Println("")
 emailOTP := &Email{}
 o = Otp{
  iOtp: emailOTP,
 }
 o.genAndSendOTP(4)
}


output:


SMS: generating random otp 1234
SMS: saving otp: 1234 to cache
SMS: sending sms: SMS OTP for login is 1234
EMAIL: generating random otp 1234
EMAIL: saving otp: 1234 to cache
EMAIL: sending email: EMAIL OTP for login is 1234

相关文章
|
2月前
|
缓存 NoSQL Go
通过 SingleFlight 模式学习 Go 并发编程
通过 SingleFlight 模式学习 Go 并发编程
|
1天前
|
安全 Go 调度
探索Go语言的并发模式:协程与通道的协同作用
Go语言以其并发能力闻名于世,而协程(goroutine)和通道(channel)是实现并发的两大利器。本文将深入了解Go语言中协程的轻量级特性,探讨如何利用通道进行协程间的安全通信,并通过实际案例演示如何将这两者结合起来,构建高效且可靠的并发系统。
|
1天前
|
安全 Go 开发者
破译Go语言中的并发模式:从入门到精通
在这篇技术性文章中,我们将跳过常规的摘要模式,直接带你进入Go语言的并发世界。你将不会看到枯燥的介绍,而是一段代码的旅程,从Go的并发基础构建块(goroutine和channel)开始,到高级模式的实践应用,我们共同探索如何高效地使用Go来处理并发任务。准备好,让Go带你飞。
|
12天前
|
SQL 关系型数据库 MySQL
Go语言项目高效对接SQL数据库:实践技巧与方法
在Go语言项目中,与SQL数据库进行对接是一项基础且重要的任务
28 11
|
27天前
|
大数据 Shell Go
GO方法与自定义类型
本文详细介绍了 Go 语言中的自定义数据类型与方法。不同于传统的面向对象编程语言,Go 通过结构体 (`struct`) 和方法 (`method`) 来扩展自定义类型的功能。文章解释了如何定义结构体、创建方法,并探讨了值接收器与指针接收器的区别及应用场景。此外,还介绍了方法的可见性以及接收器的命名惯例。通过具体示例,帮助读者更好地理解和应用这些概念。
|
2月前
|
存储 Ubuntu Go
在Ubuntu 16.04上安装Go 1.6的方法
在Ubuntu 16.04上安装Go 1.6的方法
37 1
|
2月前
|
存储 Ubuntu Go
在Ubuntu 18.04上安装Go的方法
在Ubuntu 18.04上安装Go的方法
36 1
|
2月前
|
存储 Ubuntu Linux
在Ubuntu 14.04上安装Go 1.6的方法
在Ubuntu 14.04上安装Go 1.6的方法
48 1
|
2月前
|
存储 Unix 测试技术
解释Go中常见的I/O模式
解释Go中常见的I/O模式
|
2月前
|
SQL 安全 测试技术
[go 面试] 接口测试的方法与技巧
[go 面试] 接口测试的方法与技巧