模板模式

定义

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

模板方法模式就是提供一个代码复用平台,当不变和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现。通过模板方法模式把这些行为搬到单一的地方,这样就帮助子类摆脱重复的不变行为的纠缠。

模板模式的作用

1、复用

所有的子类可以复用父类中提供的模板方法的代码

2、扩展

框架通过模板模式提供功能扩展点,让框架用户可以在不修改框架源码的情况下,基于扩展点定制化框架的功能

优点

1、封装不变部分,扩展可变部分;

2、提取公共代码,便于维护;

3、行为由父类控制,子类实现。

缺点

每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

适用范围

1、有多个子类共有的方法,且逻辑相同;

2、重要的、复杂的方法,可以考虑作为模板方法。

代码实现

考试时候试卷,对于试题部分,同一场考试内容都是一样的。试卷做完交卷只是我们每人个人填写的答案不同,那么试题就可以作为模板,我们只用去写答案。

type TestPaperImpl interface {
testQuestion1()
testQuestion2()
Answer1()
Answer2()
} type testPaper struct {
} func (t *testPaper) testQuestion1() {
fmt.Println("问题:中国有多少个民族")
} func (t *testPaper) testQuestion2() {
fmt.Println("问题:中国有多大")
} func (t *testPaper) Answer1() {
} func (t *testPaper) Answer2() {
} // 封装具体步骤
func doPaper(paper TestPaperImpl) {
paper.testQuestion1()
paper.Answer1() paper.testQuestion2()
paper.Answer2()
} type student1 struct {
*testPaper
} func (s *student1) Answer1() {
fmt.Println("答案:56")
} func (s *student1) Answer2() {
fmt.Println("答案:很大")
} type student2 struct {
*testPaper
} func (s *student2) Answer1() {
fmt.Println("答案:51")
} func (s *student2) Answer2() {
fmt.Println("答案:不知道")
}

测试文件

func TestTestPaper(t *testing.T) {
st1 := &student1{}
doPaper(st1) fmt.Println("++++++++++++++")
st2 := &student2{}
doPaper(st2)
}

结果

问题:中国有多少个民族
答案:56
问题:中国有多大
答案:很大
++++++++++++++
问题:中国有多少个民族
答案:51
问题:中国有多大
答案:不知道

结构图

回调

回调起到的作用和模板模式一样

相对于普通的函数调用来说,回调是一种双向调用关系。A类事先注册某个函数F到B类,A类在调用B类的P函数的时候,B类反过来调用A类注册给它的F函数。这里的F函数就是“回调函数”。A调用B,B反过来又调用A,这种调用机制就叫作“回调”

回调分为两种:

1、同步回调

在函数返回之前执行回调函数,同步回调看起来有点像模板模式

2、异步回调

在函数返回之后执行回调函数

如果做过支付的同学肯定很熟悉这个,例如微信支付,我们调用微信支付进行付款,成功之后我们的服务器会收到微信端支付的消息回调,然后进行支付成功之后的后续操作。

上面的考试例子使用回调实现

type testPaperCallback struct {
} func (t *testPaperCallback) testQuestion1() {
fmt.Println("问题1:中国有多少个民族")
} func (t *testPaperCallback) testQuestion2() {
fmt.Println("问题2:中国有多大")
} func (t *testPaperCallback) SubCallback(callback CallbackImpl) {
t.testQuestion1()
t.testQuestion2()
callback.Callback()
} type CallbackImpl interface {
Callback()
} type student3 struct {
*testPaperCallback
} func (s *student3) Callback() {
fmt.Println("答案1:56")
fmt.Println("答案2:测试")
} func doPaperCallback(student *student3) {
student.SubCallback(&student3{})
}

结构图

模板模式 VS 回调

从应用场景上来看,同步回调跟模板模式几乎一致。它们都是在一个大的算法骨架中,自由替换其中的某个步骤,起到代码复用和扩展的目的。而异步回调跟模板模式有较大差别,更像是观察者模式。

从代码实现上来看,回调和模板模式完全不同。回调基于组合关系来实现,把一个对象传递给另一个对象,是一种对象之间的关系;模板模式基于继承关系来实现,子类重写父类的抽象方法,是一种类之间的关系。

  • 回调可以使用匿名类来创建回调对象,可以不用事先定义类;而模板模式针对不同的实现都要定义不同的子类。

  • 如果某个类中定义了多个模板方法,每个方法都有对应的抽象方法,那即便我们只用到其中的一个模板方法,子类也必须实现所有的抽象方法。而回调就更加灵活,我们只需要往用到的模板方法中注入回调对象即可。

参考

【文中代码】https://github.com/boilingfrog/design-pattern-learning/tree/master/模板模式

【大话设计模式】https://book.douban.com/subject/2334288/

【极客时间】https://time.geekbang.org/column/intro/100039001

【模板模式】https://boilingfrog.github.io/2021/11/20/使用go实现模板模式/

设计模式学习-使用go实现模板模式的更多相关文章

  1. Java设计模式学习笔记(二) 简单工厂模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 正文开始... 1. 简介 简单工厂模式不属于GoF23中设计模式之一,但在软件开发中应用也较为 ...

  2. Java设计模式学习笔记(三) 工厂方法模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 简介 上一篇博客介绍了简单工厂模式,简单工厂模式存在一个很严重的问题: 就是当系统需要引入 ...

  3. Java设计模式学习笔记(四) 抽象工厂模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 抽象工厂模式概述 工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问 ...

  4. C#设计模式学习笔记:(13)模板方法模式

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7837716.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第一个模式--模 ...

  5. 设计模式(十四)——模板模式(SpringIOC源码分析)

    1 豆浆制作问题 编写制作豆浆的程序,说明如下: 1) 制作豆浆的流程 选材--->添加配料--->浸泡--->放到豆浆机打碎 2) 通过添加不同的配料,可以制作出不同口味的豆浆 3 ...

  6. 扯淡设计模式2:java,模板模式,

    模板模式: package com.dayuanit.service; public abstract class UserService { public void login(String use ...

  7. C#设计模式学习笔记:(23)解释器模式

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/8242238.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第十一个模式-- ...

  8. javascript设计模式学习之十三——职责链模式

    一.职责链的定义和使用场景 职责链模式的定义是,职责链模式将一系列可能会处理请求的对象连接成一条链,请求在这些对象之间一次传递,直到遇到一个可以处理它的对象.从而避免请求的发送者和接收者之间的耦合关系 ...

  9. C#设计模式学习笔记:(21)访问者模式

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/8135083.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第九个模式--访 ...

随机推荐

  1. 腾讯混合云存储 TStor 系列再添新成员,并行存储一体机正式发布

    最近国内某大型互联网公司依靠其数据优势成功上市,可见数据的重要性,而数据和存储密不可分,您真的知道自己需要更高性能存储吗? 在当今数据爆发式增长的时代,数据已经成为很多行业最重要的资源,没有之一. 数 ...

  2. 『Mivik的萌新赛 & Chino的比赛 2020』T2 题解 Galgame

    如果这是我最后一篇题解,请每年为我上坟. Galgame 题目传送门 Decription as_lky 搞到了很多 Galgame(真的很多!).一款 Galgame 可以被描述为很多场景(Scen ...

  3. 图解java 多线程模式 读书笔记

    第1章"Single Threaded Execution模式--能通过这座桥的只有一个人" 该模式可以确保执行处理的线程只能是一个,这样就可以有效防止实例不一致. 第⒉章&quo ...

  4. python中单引号、双引号和三引号

    在python中字符串可以用双引号表示,也可以用单引号表示: str1 = 'hello world'str2 = "hello world" 这两种字符串的表示方法没有区别. p ...

  5. VS2019 及 Visual Assist X 安装配置

    Visual Studio 2019 安装 下载 https://visualstudio.microsoft.com/zh-hans/downloads/ 安装 设置 扩大 Solution Con ...

  6. Servlet学习一(Servlet的使用流程)

    一.servlet运行流程 运行流程:浏览器发送请求到服务器,服务器根据url地址在webapps中寻找对应的项目文件夹然后再web.xml中检索对应的servlet,并进行调用二.servlet类写 ...

  7. mysql all_ip_test局域网IP测试工具,有需要的改一改.

    1 import threading 2 import subprocess 3 import pymysql 4 # threading.Lock() 5 6 7 class Link(object ...

  8. [对对子队]会议记录4.13(Scrum Meeting 4)

    今天已完成的工作 梁河览 ​ 工作内容:初步完成存档功能 ​ 相关issue:实现游戏内UI界面使用的组件 马嘉 ​ 工作内容:找到了原料组件 ​ 相关issue:实现游戏内UI界面使用的组件 吴昭邦 ...

  9. centOs7.6安装 mysql-8.0.27

    1.下载mysql 2.连接服务器 3.通过 rpm -qa | grep mariadb 命令查看 mariadb 的安装包 4.通过 rpm -e mariadb-libs-5.5.68-1.el ...

  10. Docker制作能够ssh连接的镜像

    本类文章只作为记录使用 命令操作: #拉取Centos 7 docker pull centos:7 #运行一个镜像 docker run -tdi --privileged centos:7 ini ...