当前位置: 首页 > news >正文

设计模式之模版方法模式(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元素&#xff0c;类型为“text/javascript"。 此标记将外部JavaScript文件添加到JSF页面。 以下JSF标记 <h:outputScript library"js" name"…...

cmake报错The link interface of target “gRPC::grpc“ contains: OpenSSL::SSL 解决

系统环境&#xff1a;麒麟V10 报错描述&#xff1a; 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语言中的空白&#xff08;空格、水平制表符、换行符&#xff09;被用于分隔Token&#xff0c;因此Token间可以有任意多个空白。 // 例1 printf("Hello, World!"); 例1中存在5个Token&#xff0c;分别是&#xff1a; printf("Hello, World! \n&qu…...

【Python】轻松解析JSON与XML:Python标准库的json与xml模块

轻松解析JSON与XML&#xff1a;Python标准库的json与xml模块 在现代数据处理与交换中&#xff0c;JSON&#xff08;JavaScript Object Notation&#xff09;和XML&#xff08;eXtensible Markup Language&#xff09;是最常用的两种数据格式。它们广泛应用于API数据传输、配置…...

物联网对商业领域的影响

互联网彻底改变了通信方式&#xff0c;并跨越了因地理障碍造成的人与人之间的鸿沟。然而&#xff0c;物联网&#xff08;IoT&#xff09;的引入通过使设备能够连接到互联网&#xff0c;改变了设备的功能。想象一下&#xff0c;你的闹钟连接到互联网&#xff0c;并且能够用你的声…...

第16章 SELECT 底层执行原理

一、SELECT查询的完整结构 1.1 方式一&#xff08;SQL 92语法&#xff09; SELECT ..., ..., ... FROM ..., ..., ... WHERE 多表的连接条件 AND 不包含组函数的过滤条件 GROUP BY ..., ... HAVING 包含组函数的过滤条件 ORDER BY ... ASC/DESC LIMIT ..., ... 1.2 方式二&a…...

python查询日志,并组装sql,修复缺失的数据

前言 由于mysql链接超时波动&#xff0c;导致数据缺失&#xff0c;需要根据日志填补数据 流程 获取确实数据的订单列表 搜索日志&#xff0c;获取请求日志 根据请求日志拼装sql 打印sql供修复数据 代码 因为我们日志打印的有问题&#xff0c;所以这里用字符串截取获取入…...

RecyclerView进阶知识讲解

在 Android 开发中&#xff0c;RecyclerView 是一种高效的列表和网格布局控件&#xff0c;用于显示大规模数据。尽管基本使用方法简单&#xff0c;但深入理解并掌握其高级进阶用法能大幅提升用户体验和应用性能。下面&#xff0c;我将从布局管理、动画和手势、自定义缓存、优化…...

C语言 函数

时间&#xff1a;2024.11.10-11.11 一、学习内容 1、什么是函数 函数&#xff1a;程序中独立的功能。将反复书写的代码&#xff0c;又不确定什么时候回用到的代码打包起来。 2、函数的基本格式 函数的定义格式&#xff08;写在main函数外&#xff09; void 函数名() { 函数…...

windows中docker安装redis和redisinsight记录

创建一个Redis运行容器&#xff0c;命令如下 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端口&#xff0c;注…...

itextpdf打印A5的问题

使用A5打印的时候&#xff0c;再生成pdf是没有问题的。下面做了一个测试&#xff0c;在打印机中&#xff0c;使用A5的纸张横向放入&#xff0c;因为是家用打印机&#xff0c;A5与A4是同一个口&#xff0c;因此只能这么放。 使用itextpdf生成pdf&#xff0c;在浏览器中预览pdf是…...

qt QUndoView详解

1、概述 QUndoView 是 Qt 框架中用于显示 QUndoStack&#xff08;撤销堆栈&#xff09;内容的视图类。它通常与 QUndoStack 一起使用&#xff0c;为用户提供了一个可视化的界面来查看和操作撤销/重做历史。QUndoView 可以显示堆栈中的每个命令&#xff0c;并允许用户通过界面进…...

python+智谱AI-实现钉钉消息自动回复

python智谱AI-实现钉钉消息自动回复 实现了电脑窗口切换&#xff0c;截图识别未读消息&#xff0c;与语言模型交互后&#xff0c;将答案带入到钉钉窗口中。偷个懒&#xff0c;直接贴代码了&#xff0c;后续不断完善注释&#xff0c;如果遇到读不懂的地方&#xff0c;欢迎交流。…...

Kafka-Eagle的配置——kafka可视化界面

通过百度网盘分享的文件&#xff1a;kafka-eagle-bin-2.0.8.tar.gz 链接&#xff1a;https://pan.baidu.com/s/1H3YONkL97uXbLTPMZHrfdg?pwdsltu 提取码&#xff1a;sltu 一、界面展示 二、软件配置 1、关闭kafka集群 kf.sh stop 2、将该软件上传到/opt/modules下 cd /opt…...

【命令操作】Linux上带宽流量监控nethogs命令详解 _ 统信 _ 麒麟 _ 方德

原文链接&#xff1a;【命令操作】Linux上带宽流量监控nethogs命令详解 | 统信 | 麒麟 | 方德 Hello&#xff0c;大家好啊&#xff01;今天带来一篇关于Linux上nethogs命令详解的文章。nethogs是一款非常实用的网络流量监控工具&#xff0c;帮助用户实时查看系统中每个进程的网…...

【入门篇】数字统计——多语言版

题目跳转&#xff1a;数字统计 题目解析&#xff1a; 这道题目要求统计在给定范围 [L, R] 内所有整数中数字 2 出现的次数。例如&#xff0c;在范围 [2, 22] 中&#xff0c;数字 2 分别在数 2、12、20、21、22 中出现的次数&#xff0c;最终出现了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…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

Unity UGUI Button事件流程

场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...