设计模式之模版方法模式(Template)
一、模版方法模式介绍
1、模版方法模式定义:
模板方法模式(template method pattern)原始定义是:在操作中定义算法的框架,将一些
步骤推迟到子类中。模板方法让子类在不改变算法结构的情况下重新定义算法的某些步骤。
模板方法中的算法可以理解为广义上的业务逻辑,并不是特指某一个实际的算法。
定义中所说的算法的框架就是模板, 包含算法框架的方法就是模板方法。
模板方法模式是一种基于继承的代码复用技术,它是一种类行为模式。
模板方法模式其结构中只存在父类与子类之间的继承关系。
模板方法的作用主要是提高程序的复用性和扩展性:
1)复用指的是,所有的子类可以复用父类中提供的模板方法代码
2)扩展指的是,框架通过模板模式提供功能扩展点,让框架用户可以在不修改框架
源码的情况下,基于扩展点定制化框架的功能。
如: 我们去医院看病一般要经过以下4个流程:挂号、取号、排队、医生问诊等,其中挂
号、 取号 、排队对每个病人是一样的,可以在父类中实现,但是具体医生如何根据
病情开药每个人都是不一样的,所以开药这个操作可以延迟到子类中实现。
二、模版方法模式原理
1、模版方法模式角色
模板方法模式的定位很清楚,就是为了解决算法框架这类特定的问题,同时明确表示需要
使用继承的结构。
模版方法模式类图如下:
               
模版方法模式包含如下角色:
抽象父类:定义一个算法所包含的所有步骤,并提供一些通用的方法逻辑。
抽象父类:负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个
基本方法构成。
具体子类:继承自抽象父类,根据需要重写父类提供的算法步骤中的某些步骤。
模版方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
基本方法:是实现算法各个步骤的方法,是模板方法的组成部分。
基本方法又可以分为三种:
1)抽象方法(Abstract Method) :一个抽象方法由抽象类声明、由其具体子类实现。
2)具体方法(Concrete Method) :一个具体方法由一个抽象类或具体类声明并实现,
其子类可以进行覆盖也可以直接继承。
3)钩子方法(Hook Method) :在抽象类中已经实现,包括用于判断的逻辑方法和需
要子类重写的空方法两种。
一般钩子方法是用于判断的逻辑方法,这类方法名一般为isXxx,返回值类型为
boolean类型。
2、用代码表示模版方法模式,
代码如下:
******************************************************** 抽象父类** @author lbf*******************************************************/
public abstract class AbstractClassTemplate {//模版方法void step1(String key){System.out.println("在模板类中 -> 执行步骤1");if(step2(key)){step3();}else{step4();}step5();}//钩子方法boolean step2(String key){System.out.println("在模板类中 -> 执行步骤2");if("x".equals(key)){return true;}return false;}//基本方法abstract void step3();//基本方法abstract void step4();//基本方法void step5(){System.out.println("在模板类中 -> 执行步骤5");}void run(String key){step1(key);}
}/******************************************************** 具体子类A** @author lbf********************************************************/
public class ConcreteClassA extends AbstractClassTemplate{@Overridevoid step3() {System.out.println("在子类A中 -> 执行步骤 3");}@Overridevoid step4() {System.out.println("在子类A中 -> 执行步骤 4");}
}/******************************************************** 具体子类B** @author lbf*******************************************************/
public class ConcreteClassB extends AbstractClassTemplate{@Overridevoid step3() {System.out.println("在子类B中 -> 执行步骤 3");}@Overridevoid step4() {System.out.println("在子类B中 -> 执行步骤 4");}
}
 
 
三、模版方法模式应用示例
以P2P公司的借款系统中有一个利息计算模块为例来看下模版方法模式的使用;
利息的计算流程是这样的:
1)用户登录系统,登录时需要输入账号密码,如果登录失败(比如用户密码错误),
系统需要给出提示
2)如果用户登录成功,则根据用户的借款的类型不同,使用不同的利息计算方式进
行计算,系统需要显示计算的利息。
示例代码如下:
/******************************************************** 账户类--抽象父类** @author lbf* @date 2024-11-06 22:14*******************************************************/
public abstract class Account {//step1 具体方法-验证用户信息是否正确public boolean validate(String account,String password){System.out.println("账号: " + account + ",密码: " + password);if(account.equalsIgnoreCase("tom") &&password.equalsIgnoreCase("123456")){return true;}else{return false;}}//step2 抽象方法-计算利息public abstract void calculate();//step3 具体方法-显示利息public void display(){System.out.println("显示利息!");}//模板方法public void handle(String account,String password){if(!validate(account,password)){System.out.println("账户或密码错误!!");return;}calculate();display();}
}/******************************************************** 借款1个月--具体子类* @author lbf* @date 2024-11-06 22:15*******************************************************/
public class LoanOneMonth extends Account{@Overridepublic void calculate() {System.out.println("借款周期30天,利率为10%!");}}/******************************************************** 借款7天--具体子类* @author lbf* @date 2024-11-06 22:16*******************************************************/
public class LoanSevenDays extends Account{@Overridepublic void calculate() {System.out.println("借款周期7天,无利息!仅收取贷款金额1%的服务费!");}@Overridepublic void display() {System.out.println("七日内借款无利息!");}
}/********************************************************* @author lbf* @date 2024-11-06 22:16*******************************************************/
public class Test {public static void main(String[] args) {Account a1 = new LoanSevenDays();a1.handle("tom","12345");System.out.println("==========================");Account a2 = new LoanOneMonth();a2.handle("zhudy","123456789");}
} 
四、模版方法模式总结
1、模版方法模式优点
1)在父类中形式化的定义一个算法,而由它的子类来实现细节处理,在子类实现详细的
处理代码时,并不会改变父类算法中步骤的执行顺序
2)模板方法可以实现一种反向的控制结构,通过子类覆盖父类的钩子方法,来决定某一个
特定步骤是否需要执行
3)在模板方法模式中可以通过子类来覆盖父类的基本方法,不同的子类可以提供基本方法
的不同实现,更换和增加新的子类很方便,符合单一职责原则和开闭原则
 2、模版方法模式缺点
1)对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,
设计也更加抽象
2)父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向
的控制结构,它提高了代码阅读的难度。
3、模版方法模式适用场景
1)多个类有相同的方法并且逻辑可以共用时;
2)将通用的算法(业务流程)或固定流程设计为模板,在每一个具体的子类中再继续
优化算法步骤或流程步骤时;
3)重构超长代码时,发现某一个经常使用的公有方法。
相关文章:
设计模式之模版方法模式(Template)
一、模版方法模式介绍 1、模版方法模式定义: 模板方法模式(template method pattern)原始定义是:在操作中定义算法的框架,将一些 步骤推迟到子类中。模板方法让子类在不改变算法结构的情况下重新定义算法的某些步骤。 模板方法中的算法可以理…...
背包九讲——背包问题求具体方案
目录 背包问题求具体方案 1. 01 背包问题 题目:12. 背包问题求具体方案 - AcWing题库 算法思路: 代码实现: 2. 多重背包问题 算法思路: 3. 完全背包问题 算法思路: 代码实现: 背包问题第九讲—…...
Python http打印(http打印body)flask demo(http调试demo、http demo、http printer)
文章目录 代码解释 代码 # flask_http_printer.pyfrom flask import Flask, request, jsonify import jsonapp Flask(__name__)app.route(/printinfo, methods[POST]) def print_info():# 分隔符separator "-" * 60# 获取请求头headers request.headers# 获取 JS…...
JSF HTML标签教程一口气讲完!(下)
JSF OutputScript示例 JSF教程 - JSF OutputScript示例 h:outputScript标记渲染类型为“script"的HTML元素,类型为“text/javascript"。 此标记将外部JavaScript文件添加到JSF页面。 以下JSF标记 <h:outputScript library"js" name"…...
cmake报错The link interface of target “gRPC::grpc“ contains: OpenSSL::SSL 解决
系统环境:麒麟V10 报错描述: The link interface of target "gRPC::grpc" contains: OpenSSL::SSL but the target was not found. Possible reasons include: * There is a typo in the target name. * A find_package call is missing fo…...
C语言PythonBash:空白(空格、水平制表符、换行符)与转义字符
C语言 空白 C语言中的空白(空格、水平制表符、换行符)被用于分隔Token,因此Token间可以有任意多个空白。 // 例1 printf("Hello, World!"); 例1中存在5个Token,分别是: printf("Hello, World! \n&qu…...
【Python】轻松解析JSON与XML:Python标准库的json与xml模块
轻松解析JSON与XML:Python标准库的json与xml模块 在现代数据处理与交换中,JSON(JavaScript Object Notation)和XML(eXtensible Markup Language)是最常用的两种数据格式。它们广泛应用于API数据传输、配置…...
物联网对商业领域的影响
互联网彻底改变了通信方式,并跨越了因地理障碍造成的人与人之间的鸿沟。然而,物联网(IoT)的引入通过使设备能够连接到互联网,改变了设备的功能。想象一下,你的闹钟连接到互联网,并且能够用你的声…...
第16章 SELECT 底层执行原理
一、SELECT查询的完整结构 1.1 方式一(SQL 92语法) SELECT ..., ..., ... FROM ..., ..., ... WHERE 多表的连接条件 AND 不包含组函数的过滤条件 GROUP BY ..., ... HAVING 包含组函数的过滤条件 ORDER BY ... ASC/DESC LIMIT ..., ... 1.2 方式二&a…...
python查询日志,并组装sql,修复缺失的数据
前言 由于mysql链接超时波动,导致数据缺失,需要根据日志填补数据 流程 获取确实数据的订单列表 搜索日志,获取请求日志 根据请求日志拼装sql 打印sql供修复数据 代码 因为我们日志打印的有问题,所以这里用字符串截取获取入…...
RecyclerView进阶知识讲解
在 Android 开发中,RecyclerView 是一种高效的列表和网格布局控件,用于显示大规模数据。尽管基本使用方法简单,但深入理解并掌握其高级进阶用法能大幅提升用户体验和应用性能。下面,我将从布局管理、动画和手势、自定义缓存、优化…...
C语言 函数
时间:2024.11.10-11.11 一、学习内容 1、什么是函数 函数:程序中独立的功能。将反复书写的代码,又不确定什么时候回用到的代码打包起来。 2、函数的基本格式 函数的定义格式(写在main函数外) void 函数名() { 函数…...
windows中docker安装redis和redisinsight记录
创建一个Redis运行容器,命令如下 docker run -it -d --name redis -p 6379:6379 redis --bind 0.0.0.0 --protected-mode no -d 代表Redis容器后台运行 --name redis 给创建好的容器起名叫redis -p 6379:6379 将容器的6379端口映射到宿主机的6379端口,注…...
itextpdf打印A5的问题
使用A5打印的时候,再生成pdf是没有问题的。下面做了一个测试,在打印机中,使用A5的纸张横向放入,因为是家用打印机,A5与A4是同一个口,因此只能这么放。 使用itextpdf生成pdf,在浏览器中预览pdf是…...
qt QUndoView详解
1、概述 QUndoView 是 Qt 框架中用于显示 QUndoStack(撤销堆栈)内容的视图类。它通常与 QUndoStack 一起使用,为用户提供了一个可视化的界面来查看和操作撤销/重做历史。QUndoView 可以显示堆栈中的每个命令,并允许用户通过界面进…...
python+智谱AI-实现钉钉消息自动回复
python智谱AI-实现钉钉消息自动回复 实现了电脑窗口切换,截图识别未读消息,与语言模型交互后,将答案带入到钉钉窗口中。偷个懒,直接贴代码了,后续不断完善注释,如果遇到读不懂的地方,欢迎交流。…...
Kafka-Eagle的配置——kafka可视化界面
通过百度网盘分享的文件:kafka-eagle-bin-2.0.8.tar.gz 链接:https://pan.baidu.com/s/1H3YONkL97uXbLTPMZHrfdg?pwdsltu 提取码:sltu 一、界面展示 二、软件配置 1、关闭kafka集群 kf.sh stop 2、将该软件上传到/opt/modules下 cd /opt…...
【命令操作】Linux上带宽流量监控nethogs命令详解 _ 统信 _ 麒麟 _ 方德
原文链接:【命令操作】Linux上带宽流量监控nethogs命令详解 | 统信 | 麒麟 | 方德 Hello,大家好啊!今天带来一篇关于Linux上nethogs命令详解的文章。nethogs是一款非常实用的网络流量监控工具,帮助用户实时查看系统中每个进程的网…...
【入门篇】数字统计——多语言版
题目跳转:数字统计 题目解析: 这道题目要求统计在给定范围 [L, R] 内所有整数中数字 2 出现的次数。例如,在范围 [2, 22] 中,数字 2 分别在数 2、12、20、21、22 中出现的次数,最终出现了6次。 题目的输入为两个正…...
探索那些现代C++语法糖
本文来聊聊现代C的一些语法糖。 1.Auto auto x 10; // 推导为 int auto y 3.14; // 推导为 double2.范围-based for 循环 std::vector<int> v {1, 2, 3, 4, 5}; for (auto val : v) {std::cout << val << " "; }3.nullptr int* ptr nullpt…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
