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

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

GoLang设计模式16 - 模板方法模式的更多相关文章

  1. 乐在其中设计模式(C#) - 模板方法模式(Template Method Pattern)

    原文:乐在其中设计模式(C#) - 模板方法模式(Template Method Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 模板方法模式(Template Method ...

  2. 折腾Java设计模式之模板方法模式

    博客原文地址:折腾Java设计模式之模板方法模式 模板方法模式 Define the skeleton of an algorithm in an operation, deferring some ...

  3. Golang设计模式—简单工厂模式(Simple Factory Pattern)

    Golang设计模式--简单工厂模式 背景 假设我们在做一款小型翻译软件,软件可以将德语.英语.日语都翻译成目标中文,并显示在前端. 思路 我们会有三个具体的语言翻译结构体,或许以后还有更多,但现在分 ...

  4. js设计模式——6.模板方法模式与职责链模式

    js设计模式——6.模板方法模式与职责链模式 职责链模式

  5. java设计模式之模板方法模式

    模板方法模式 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中. 模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤.通俗的说的就是有很多相同的步骤的,在某一些地方可能有一些差 ...

  6. C#设计模式(14)——模板方法模式(Template Method)

    一.引言 提到模板,大家肯定不免想到生活中的“简历模板”.“论文模板”.“Word中模版文件”等,在现实生活中,模板的概念就是——有一个规定的格式,然后每个人都可以根据自己的需求或情况去更新它,例如简 ...

  7. 【GOF23设计模式】模板方法模式

    来源:http://www.bjsxt.com/ 一.[GOF23设计模式]_模板方法模式.钩子函数.方法回调.好莱坞原则 package com.test.templateMethod; publi ...

  8. [设计模式] 22 模板方法模式 template

    转http://www.jellythink.com/archives/407 在GOF的<设计模式:可复用面向对象软件的基础>一书中对模板方法模式是这样说的:定义一个操作中的算法骨架,而 ...

  9. java_设计模式_模板方法模式_Template Method Pattern(2016-08-11)

    定义: 定义一个操作中算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构即可重定义该算法中的某些特定步骤.这里的算法的结构,可以理解为你根据需求设计出来的业务流程.特定的步骤就是指那些 ...

随机推荐

  1. 浅谈机(J)惨(C)技巧——从入门到精通(?)

    JC总是无聊的机房中有意思的一个瞬间... 比如: 这个杰作由 ZSWBWYX 完成 你认为这只是AK-IOI吗?不!注意用户名...也是此人的杰作. 所以,在险恶的机房里,一定要保护好自己的账号. ...

  2. WPF进阶技巧和实战08-依赖属性与绑定02

    将元素绑定在一起 数据绑定最简单的形式是:源对象是WPF元素而且源属性是依赖项属性.依赖项属性内置了更改通知支持,当源对象中改变依赖项属性时,会立即更新目标对象的绑定属性. 元素绑定到元素也是经常使用 ...

  3. 分片利器 AutoTable:为用户带来「管家式」分片配置体验

    在<DistSQL:像数据库一样使用 Apache ShardingSphere>一文中,Committer 孟浩然为大家介绍了 DistSQL 的设计初衷和语法体系,并通过实战操作展示了 ...

  4. 题解 [SBCOI2020] 一直在你身旁

    题目传送门 题目大意 给出一个长度为 \(n\) 的单调不减的序列,每次可以选出一个点,产生贡献 \(a_k\),我们可以得知我们需要找到的数是否大于 \(k\).问找到要找到的数最小花费. \(n\ ...

  5. 自定义Push/Pop和Present/Dismiss转场

    项目概述 iOS中最常见的动画无疑是Push和Pop的转场动画了,其次是Present和Dismiss的转场动画. 如果我们想自定义这些转场动画,苹果其实提供了相关的API,在自定义转场之前,我们需要 ...

  6. 【Java虚拟机9】类加载器之命名空间详解

    前言 前面介绍类加载器的时候,介绍了一下命名空间这个概念.今天就通过一个例子,来详细了解一下[类加载器的命名空间].然后通过这个例子,我们可以总结一下双亲委托模型的好处与优点. 例1(不删除class ...

  7. JVM:内存结构

    JVM:内存结构 说明:这是看了 bilibili 上 黑马程序员 的课程 JVM完整教程 后做的笔记 内容 程序计数器 虚拟机栈 本地方法栈 堆 方法区 直接内存 1. 程序计数器 1.1 定义 P ...

  8. AIApe问答机器人Scrum Meeting 4.23

    Scrum Meeting 1 日期:2021年4月23日 会议主要内容概述:各成员汇报进度情况,前后端针对WebAPI进行协调与统一工作. 一.进度情况 组员 负责 两日内已完成的工作 后两日计划完 ...

  9. oo第三次博客-JML规格

    这三周的作业主要是围绕以JML来约束代码开发,以确保程序的正确性与鲁棒性. Part 1:三次作业的实现与bug 第一次作业没有任何算法和数据结构上的难度,对于Path和PathContainer的各 ...

  10. WEB前端工程师如何做职业规划?

    对于一个WEB前端的职业规划,其实是有各种的答案,没有哪种答案是完全正确的,全凭自己的选择,只要是自己选定了,坚持去认真走,就好.在这里, 我只是 简要说一下自己对于这块儿内容的理解.有一个观点想要分 ...