行为型模式-模板方法模式
模板方法模式
概述
在面向对象程序设计过程中,程序员常常会遇到这种情况:设计一个系统时知道了算法所需的关键步骤,而且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关。
例如,去银行办理业务一般要经过以下4个流程:取号、排队、办理具体业务、对银行工作人员进行评分等,其中取号、排队和对银行工作人员进行评分的业务对每个客户是一样的,可以在父类中实现,但是办理具体业务却因人而异,它可能是存款、取款或者转账等,可以延迟到子类中实现。
定义:
定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
结构
模板方法(Template Method)模式包含以下主要角色:
-
抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。
-
模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
-
基本方法:是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又可以分为三种:
-
抽象方法(Abstract Method) :一个抽象方法由抽象类声明、由其具体子类实现。
-
具体方法(Concrete Method) :一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承。
-
钩子方法(Hook Method) :在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。
一般钩子方法是用于判断的逻辑方法,这类方法名一般为isXxx,返回值类型为boolean类型。
-
-
-
具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的组成步骤。
案例实现
【例】炒菜
炒菜的步骤是固定的,分为倒油、热油、倒蔬菜、倒调料品、翻炒等步骤。现通过模板方法模式来用代码模拟。类图如下:

代码如下:
public abstract class AbstractClass {public final void cookProcess() {//第一步:倒油this.pourOil();//第二步:热油this.heatOil();//第三步:倒蔬菜this.pourVegetable();//第四步:倒调味料this.pourSauce();//第五步:翻炒this.fry();}public void pourOil() {System.out.println("倒油");}//第二步:热油是一样的,所以直接实现public void heatOil() {System.out.println("热油");}//第三步:倒蔬菜是不一样的(一个下包菜,一个是下菜心)public abstract void pourVegetable();//第四步:倒调味料是不一样public abstract void pourSauce();//第五步:翻炒是一样的,所以直接实现public void fry(){System.out.println("炒啊炒啊炒到熟啊");}
}public class ConcreteClass_BaoCai extends AbstractClass {@Overridepublic void pourVegetable() {System.out.println("下锅的蔬菜是包菜");}@Overridepublic void pourSauce() {System.out.println("下锅的酱料是辣椒");}
}public class ConcreteClass_CaiXin extends AbstractClass {@Overridepublic void pourVegetable() {System.out.println("下锅的蔬菜是菜心");}@Overridepublic void pourSauce() {System.out.println("下锅的酱料是蒜蓉");}
}public class Client {public static void main(String[] args) {//炒手撕包菜ConcreteClass_BaoCai baoCai = new ConcreteClass_BaoCai();baoCai.cookProcess();//炒蒜蓉菜心ConcreteClass_CaiXin caiXin = new ConcreteClass_CaiXin();caiXin.cookProcess();}
}
注意:为防止恶意操作,一般模板方法都加上 final 关键词。
优缺点
优点:
-
提高代码复用性
将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中。
-
实现了反向控制
通过一个父类调用其子类的操作,通过对子类的具体实现扩展不同的行为,实现了反向控制 ,并符合“开闭原则”。
缺点:
- 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。
- 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。
适用场景
- 算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现。
- 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。
JDK源码解析
InputStream类就使用了模板方法模式。在InputStream类中定义了多个 read() 方法,如下:
public abstract class InputStream implements Closeable {//抽象方法,要求子类必须重写public abstract int read() throws IOException;public int read(byte b[]) throws IOException {return read(b, 0, b.length);}public int read(byte b[], int off, int len) throws IOException {if (b == null) {throw new NullPointerException();} else if (off < 0 || len < 0 || len > b.length - off) {throw new IndexOutOfBoundsException();} else if (len == 0) {return 0;}int c = read(); //调用了无参的read方法,该方法是每次读取一个字节数据if (c == -1) {return -1;}b[off] = (byte)c;int i = 1;try {for (; i < len ; i++) {c = read();if (c == -1) {break;}b[off + i] = (byte)c;}} catch (IOException ee) {}return i;}
}
从上面代码可以看到,无参的 read() 方法是抽象方法,要求子类必须实现。而 read(byte b[]) 方法调用了 read(byte b[], int off, int len) 方法,所以在此处重点看的方法是带三个参数的方法。
在该方法中第18行、27行,可以看到调用了无参的抽象的 read() 方法。
总结如下: 在InputStream父类中已经定义好了读取一个字节数组数据的方法是每次读取一个字节,并将其存储到数组的第一个索引位置,读取len个字节数据。具体如何读取一个字节数据呢?由子类实现。
相关文章:
行为型模式-模板方法模式
模板方法模式 概述 在面向对象程序设计过程中,程序员常常会遇到这种情况:设计一个系统时知道了算法所需的关键步骤,而且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关…...
IPsec中IKE与ISAKMP过程分析(快速模式-消息1)
IPsec中IKE与ISAKMP过程分析(主模式-消息1)_搞搞搞高傲的博客-CSDN博客 IPsec中IKE与ISAKMP过程分析(主模式-消息2)_搞搞搞高傲的博客-CSDN博客 IPsec中IKE与ISAKMP过程分析(主模式-消息3)_搞搞搞高傲的博客…...
PostgreSQL 数据类型转换
各种数据类型(日期/时间、integer、floating point和numeric)转换成格式化的字符串及反过来从格式化的字符串转换成指定的数据类型,在实际操作中经常遇到。下面总结了一些常用的函数。 日期操作函数 函数返回类型描述实例to_char(timestamp…...
【Java笔试强训 1】
🎉🎉🎉点进来你就是我的人了博主主页:🙈🙈🙈戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔🦾🦾🦾 目录 一、选择题 二、编程题 🔥组队竞…...
你买票了吗?五一火车票发售量创历史新高,车票总发售2209万张票
五一劳动节已经成为了除春节国庆节外最隆重的节日,是全国性的庆祝节日。在这个节日里,人们可以通过旅游、购物、娱乐等方式来放松身心,充满活力地迎接新的挑战。同时,五一假期也成为了国内外客流量最大的旅游黄金周之一࿰…...
DiffUtil的使用
RecyclerView的DiffUtil用于计算并更新RecyclerView中数据集的变化。通过使用DiffUtil,我们可以避免完全重新加载整个列表,并且只会更改必要的视图。 以下是DiffUtil的基本用法: 创建一个继承自DiffUtil.Callback的类来计算差异。在这个类中…...
【Python】【进阶篇】18、Django初始化项目环境精讲
目录 18、Django初始化项目环境精讲1. 完成数据库迁移2. PyMySQL模块的使用3. migrate与makemigrations命令详解1) makegrations生成数据库迁移文件2) migrate执行数据库迁移命令3) 完成数据库迁移总结 18、Django初始化项目环境精讲 上一节中,我们完成了对 settin…...
Web前端基础
一.说明 如果你要了解web前端领域,那么三种语言是你必须要了解的,即html5、CSS、Javascript是你必须要了解的,通过前面的专栏内容你一定对html标记语言非常熟悉,那么其他两种语言是什么,他们怎么和html联系在一起&…...
ACM 1007 | 分段函数求值
文章目录 0x00 前言 0x01 题目描述 0x02 问题分析 0x03 代码设计 0x04 完整代码 0x05 运行效果 0x06 总结 0x00 前言 C 语言网不仅提供 C 语言,还包括 C 、 java 、算法与数据结构等课程在内的各种入门教程、视频录像、编程经验、编译器教程及软件下载、题解博…...
ChatGPT技术原理 第十四章:未来发展方向
目录 14.1 多模态对话生成 14.2 跨语言对话生成 14.3 增量学习 14.4 深度强化学习...
大型水利投资集团,打造数智财资管理新范式
随着我国城市化进程的不断推进,城市基础设施在国民经济中的作用愈加重要,其建设水平直接影响一个城市的竞争力。国有城投、水投等企业作为城市基础设施建设的主要参与者,其重要性不言而喻。随着国家、地方对基础设施重要性认识的加深以及政府…...
【java】彻底剖析 Synchronized
文章目录 前言对象结构Monitor 对象Synchronized特征原子性可见性有序性可重入锁 锁升级的过程 前言 源码级别剖析Synchronized 对象结构 Synchronized是Java中的隐式锁,它的获取锁和释放锁都是隐式的,完全交由JVM帮助我们操作,在了解Sync…...
有反爬机制就爬不了吗?那是你还不知道反反爬,道高一尺魔高一丈啊
文章目录 一、从用户请求的Headers反爬虫二、基于用户行为反爬虫(1)方法1(2)方法2 三、动态页面的反爬虫四.总结 不知道你们在用爬虫爬数据的时候是否有发现,越来越多的网站都有自己的反爬机制,抓取数据已经…...
手把手教你本地CPU环境部署清华大模型ChatGLM-6B,利用量化模型,本地即可开始智能聊天,达到ChatGPT的80%
大家好,我是微学AI,今天教你们本地CPU环境部署清华大ChatGLM-6B模型,利用量化模型,每个人都能跑动大模型。ChatGLM-6B是一款出色的中英双语对话模型,拥有超过62亿个参数,可高效地处理日常对话场景。与GLM-1…...
FFmpeg 自定义IO CONTEXT实现音频解码,以及seek函数
对于从音频流buffer中解码的场景中,我们需要实现自己的io context 去从buffer中解码,参考ffmepg官方实例:doc/examples/avio_reading.c 关于是否要实现avio context中的seek函数,需要看需要解码什么格式,大部分格式不…...
技能升级(2023寒假每日一题 13)
小蓝最近正在玩一款 RPG 游戏。 他的角色一共有 N N N 个可以加攻击力的技能。 其中第 i i i 个技能首次升级可以提升 A i A_i Ai 点攻击力,以后每次升级增加的点数都会减少 B i B_i Bi。 ⌈ A i / B i ⌉ ⌈A_i/B_i⌉ ⌈Ai/Bi⌉(上取整&a…...
低频量化之 可转债 配债数据及策略 - 全网独家
目录 历史文章可转债配债数据 待发转债(进展统计)待发转债(行业统计)待发转债(5证监会通过,PE排序)待发转债(5证监会通过,安全垫排序)待发转债(5证…...
Code area 和Data area的区别
Code Area FLASH :程序在这个flash运行时,几乎没有延时, 运行速度以时钟设置为准。 Data Area FLASH: 程序在这段flash运行时,每条语句都有延时, 最后的速度可能是以10M为时钟(举例)…...
Oracle LiveLabs DB Security (数据库安全)实验汇总
在Oracle LiveLabs中,和数据库安全相关的实验分为2个系列,共12个实验。 Oracle数据库安全架构如下图: 这些实验涉及了Oracle安全相关的特性,企业版选件,独立产品和服务。 关于Oracle安全产品的中文主页可见&#…...
PAT A1012 The Best Rank
1012 The Best Rank 分数 25 作者 CHEN, Yue 单位 浙江大学 To evaluate the performance of our first year CS majored students, we consider their grades of three courses only: C - C Programming Language, M - Mathematics (Calculus or Linear Algrbra), and E -…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...
用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法
用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法 大家好,我是Echo_Wish。最近刷短视频、看直播,有没有发现,越来越多的应用都开始“懂你”了——它们能感知你的情绪,推荐更合适的内容,甚至帮客服识别用户情绪,提升服务体验。这背后,神经网络在悄悄发力,撑起…...
32位寻址与64位寻址
32位寻址与64位寻址 32位寻址是什么? 32位寻址是指计算机的CPU、内存或总线系统使用32位二进制数来标识和访问内存中的存储单元(地址),其核心含义与能力如下: 1. 核心定义 地址位宽:CPU或内存控制器用32位…...
