[go] 模版方法模式

模版方法模式

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

模型说明

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

优缺点

1.优点

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

2.缺点

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

使用场景

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

参考代码

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

  1. 生成随机的 n 位数字。
  2. 在缓存中保存这组数字以便进行后续验证。
  3. 准备内容。
  4. 发送通知。
go 复制代码
// 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
}
go 复制代码
// 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
}
go 复制代码
// 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
}
go 复制代码
// 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:

go 复制代码
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
相关推荐
2739920295 分钟前
生成二维码 QRCode (QT)
开发语言·qt
火山灿火山15 分钟前
初识Qt(使用不同中方式创建helloworld)
开发语言·qt
gadiaola20 分钟前
【计算机网络面试篇】HTTP
java·后端·网络协议·计算机网络·http·面试
bcbnb23 分钟前
HTTP抓包工具Fiddler使用教程,代理设置、HTTPS配置与接口调试实战指南
后端
昕昕恋恋40 分钟前
Kotlin 中类成员访问权限的实践与辨析
后端
BD_Marathon44 分钟前
sbt 编译打包 scala
开发语言·后端·scala
雾岛听蓝1 小时前
C++ 入门核心知识点(从 C 过渡到 C++ 基础)
开发语言·c++·经验分享·visual studio
有风631 小时前
优先级队列详解
后端
7***37451 小时前
Java设计模式之工厂
java·开发语言·设计模式
雨中飘荡的记忆1 小时前
ByteBuddy 实战指南
后端