Go设计模式(19)-模板模式

模板模式定义算法骨架,使用上有两个特征,一是要继承算法骨架,达到复用的目的;二是具体的算法步骤在子类中实现,达到扩展的目的。

UML类图位置:https://www.processon.com/view/link/60d29bf3e401fd49502afd25

本文代码链接为:https://github.com/shidawuhen/asap/blob/master/controller/design/19template.go

1.定义

1.1模板模式

模板模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

UML:

图片

1.2分析

模板模式的UML图几乎是最简单的了。

**模板方法模式可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤。**TemplateMethod是算法骨架,PrimitiveOperation1和PrimitiveOperation2是骨架中的某些步骤。

在模板模式经典的实现中,模板方法定义为 final,可以避免被子类重写。需要子类重写的方法定义为 abstract,可以强迫子类去实现。

以前用这种定义好算法骨架,具体实现在不同子类的方案时,一般使用的是工厂方法加代理模式。工厂方法能够提供更多的灵活性,但如果一个算法骨架中有10个具体算法,总不能让工厂生产10个不同的对象吧。所以如果算法骨架中有多个具体算法,而这些算法又是高内聚的,用模板模式就很合适。

2.使用场景

业务开发场景中,模板模式使用频率并不高,但是在框架方面,还是使用的比较频繁的。

先查看了Gin源码Gin源码剖析,发现用的不是模板模式,其实完全没用啥设计模式,算是用了里氏替换原则。

主框架有Handler接口,用于做路由解析、对应逻辑执行与返回。

type Handler interface {
    
    
   ServeHTTP(ResponseWriter, *Request)
}

Gin中的engin实现该接口

// ServeHTTP conforms to the http.Handler interface.
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    
    
   c := engine.pool.Get().(*Context)
   c.writermem.reset(w)
   c.Request = req
   c.reset()

   engine.handleHTTPRequest(c)

   engine.pool.Put(c)
}

之所以说没有使用模板模式,主要是因为并没有继承算法框架。

后来想想Go语言没有继承,没法实现经典款模板方法。虽然可以用组合实现模板方法,但无法控制对算法框架的重写、也无法强迫子类重写算法实现,感觉价值不大。有很多更好的方案能够实现目的。

3.代码实现

虽然没什么特别好的case,但是代码还是要写一下的。参考大话设计模式,写一个试卷场景吧。试卷内容确定,但试卷答案不定。

package main

import "fmt"

/**
 * @Author: Jason Pang
 * @Description: 试卷
 */
type Examination struct {
    
    
   //函数变量,回答问题1
   Answer1 func()
   //函数变量,回答问题2
   Answer2 func()
}

/**
 * @Author: Jason Pang
 * @Description: 问题列表,也是算法骨架
 * @receiver e
 */
func (e *Examination) Questions() {
    
    
   fmt.Println("第一题:谁是最帅的人?")
   e.Answer1()
   fmt.Println("第二题:生活的意义是什么?")
   e.Answer2()
}

/**
 * @Author: Jason Pang
 * @Description: 真正做试卷
 */
type ExamplationDo struct {
    
    
   Examination
}

/**
 * @Author: Jason Pang
 * @Description: 写答案1
 * @receiver d
 */
func (d *ExamplationDo) Answer1() {
    
    
   fmt.Println("答案:我自己")
}

/**
 * @Author: Jason Pang
 * @Description: 写答案2
 * @receiver d
 */
func (d *ExamplationDo) Answer2() {
    
    
   fmt.Println("答案:躺平")
}
func main() {
    
    
   e := &ExamplationDo{
    
    }
   //需要对父类函数进行赋值
   e.Examination.Answer1 = e.Answer1
   e.Examination.Answer2 = e.Answer2

   e.Questions()
}

输出:

➜ myproject go run main.go

第一题:谁是最帅的人?

答案:我自己

第二题:生活的意义是什么?

答案:躺平

上面的代码使用一些技巧才能实现模板模式。父类Examination实现了算法骨架,同时包含两个函数变量Answer1和Answer2,代表算法实现。子类ExamplationDo实现了Answer1和Answer2,并将这两个函数赋值给父类的函数变量。

总结

模板模式有两大作用:复用和扩展。其中,复用指的是,所有的子类可以复用父类中提供的模板方法的代码。扩展指的是,框架通过模板模式提供功能扩展点,让框架用户可以在不修改框架源码的情况下,基于扩展点定制化框架的功能。

最后

大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)

我的个人博客为:https://shidawuhen.github.io/

图片

往期文章回顾:

招聘

  1. 字节跳动|内推大放送

  2. 字节跳动|今日头条广州服务端研发工程师内推

  3. 字节跳动|抖音电商急招上海前端开发工程

  4. 字节跳动|抖音电商上海资深服务端开发工程师-交易

  5. 字节跳动|抖音电商武汉服务端(高级)开发工程师

  6. 字节跳动|飞书大客户产品经理内推咯

  7. 字节跳动|抖音电商服务端技术岗位虚位以待

  8. 字节跳动招聘专题

设计模式

  1. Go设计模式(18)-观察者模式

  2. Go设计模式(17)-享元模式

  3. Go设计模式(16)-组合模式

  4. Go设计模式(15)-门面模式

  5. Go设计模式(14)-适配器模式

  6. Go设计模式(13)-装饰器模式

  7. Go设计模式(12)-桥接模式

  8. Go设计模式(11)-代理模式

  9. Go设计模式(10)-原型模式

  10. Go设计模式(9)-建造者模式

  11. Go设计模式(8)-抽象工厂

  12. Go设计模式(7)-工厂模式

  13. Go设计模式(6)-单例模式

  14. Go设计模式(5)-类图符号表示法

  15. Go设计模式(4)-代码编写优化

  16. Go设计模式(4)-代码编写

  17. Go设计模式(3)-设计原则

  18. Go设计模式(2)-面向对象分析与设计

  19. Go设计模式(1)-语法

语言

  1. 再也不怕获取不到Gin请求数据了

  2. 一文搞懂pprof

  3. Go工具之generate

  4. Go单例实现方案

  5. Go通道实现原理

  6. Go定时器实现原理

  7. Beego框架使用

  8. Golang源码BUG追查

  9. Gin框架简洁版

  10. Gin源码剖析

架构

  1. 分页复选设计的坑

  2. 支付接入常规问题

  3. 限流实现2

  4. 秒杀系统

  5. 分布式系统与一致性协议

  6. 微服务之服务框架和注册中心

  7. 浅谈微服务

  8. 限流实现1

  9. CDN请求过程详解

  10. 常用缓存技巧

  11. 如何高效对接第三方支付

  12. 算法总结

存储

  1. 一文搞懂MySQL数据库分库分表

  2. MySQL开发规范

  3. Redis实现分布式锁

  4. 事务原子性、一致性、持久性的实现原理

  5. InnoDB锁与事务简析

网络

  1. HTTP2.0基础教程

  2. HTTPS配置实战

  3. HTTPS连接过程

  4. TCP性能优化

工具

  1. GoLand实用技巧

  2. 根据mysql表自动生成go struct

  3. Markdown编辑器推荐-typora

读书笔记

  1. 《毛选》推荐

  2. 原则

  3. 资治通鉴

  4. 敏捷革命

  5. 如何锻炼自己的记忆力

  6. 简单的逻辑学-读后感

  7. 热风-读后感

  8. 论语-读后感

  9. 孙子兵法-读后感

思考

  1. 对过去的一点回顾

  2. 对写博客的一些思考

  3. 晚上打119的经历

  4. 为动员一切力量争取胜利而斗争

  5. 反对自由主义

  6. 实践论

  7. 评价自己的标准

  8. 2020博客总结

  9. 服务端团队假期值班方案

  10. 项目流程管理

  11. 对项目管理的一些看法

  12. 对产品经理的一些思考

  13. 关于程序员职业发展的思考

  14. 关于代码review的思考

Guess you like

Origin blog.csdn.net/shida219/article/details/118380545