<设计模式修炼>模板方法模式的使用场景和注意事项学习
介绍
模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
2) 简单说,模板方法模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定 步骤
3) 这种类型的设计模式属于行为型模式
场景
编写制作豆浆的程序,说明如下:
- 制作豆浆的流程 选材—>添加配料—>浸泡—>放到豆浆机打碎
- 通过添加不同的配料,可以制作出不同口味的豆浆
- 选材、浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的
- 请使用 模板方法模式 完成 (说明:因为模板方法模式,比较简单,很容易就想到这个方案,因此就直接使用,不再使用传统的方案来引出模板方法模式 )
代码演示:
1.定义抽象类,提供抽象方法
SoyaMilk是抽象类,make是制作豆浆的抽象方法,只需要根据放入原料的不同就可以制造不同口味的豆浆,所以添加原料是一个抽象方法,交给子类去实现,调用的时候通过不同的子类对象就可以制作不同口味的豆浆
public abstract class SoyaMilk {
final void make(){select();addCondiments();soak();bead();}void select(){System.out.println("1.选择新鲜黄豆");
}abstract void addCondiments();void soak(){System.out.println("3.开始浸泡");
}void bead(){System.out.println("4.黄豆和配料放在豆浆机打碎");
}
}
2.提供子类重写抽象方法
制作花生豆浆子类:
public class PeanutSoyaMilk extends SoyaMilk {@Overridevoid addCondiments() {System.out.println("2.添加花生原料");}
}
制作红豆豆浆子类:
public class RedBeanSoyaMilk extends SoyaMilk{@Overridevoid addCondiments() {System.out.println("2.添加红豆配料");}
}
3.方法测试
public class TemplateTest {public static void main(String[] args) {SoyaMilk peanutSoyaMilk = new PeanutSoyaMilk();SoyaMilk redBeanSoyaMilk = new RedBeanSoyaMilk();peanutSoyaMilk.make();redBeanSoyaMilk.make();}
}
运行结果:
钩子方法
1.在模板方法模式的父类中,我们可以定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为“钩子”。
2.还是用上面做豆浆的例子来讲解,比如,我们还希望制作纯豆浆,不添加任何的配料,请使用钩子方法对前面的模板方法进行改造
抽象方法改造,提供空实现
void addCondiments(){};
制作原味豆浆实现类
public class OriginalMilk extends SoyaMilk{@Overridevoid addCondiments() {super.addCondiments();}
}
子类视情况而定是否要覆盖父类方法。
框架源码体现
在Spring源码中,就使用到了模板方法模式,就在容器刷新的方法中
ConfigurableApplicationContext接口中定义了一个抽象方法refresh
在其实现类AbstractApplicationContext中实现了这个模板方法
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}
}
这个方法是Spring最重要的容器刷新的方法,我们看看在refresh方法中Spring通过模板方法模式留下了多少扩展点
1.obtainFreshBeanFactory()方法
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {refreshBeanFactory();return getBeanFactory();}
在obtainFreshBeanFactory的方法中refreshBeanFactory()和getBeanFactory()都是抽象方法,只能子类去实现,主要是为了初始化Spring容器并获取子类创建的BeanFactoy
2.postProcessBeanFactory(beanFactory)方法
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {}
它是一个钩子方法,交给子类去实现
3.onRefresh()方法
protected void onRefresh() throws BeansException {// For subclasses: do nothing by default.}
它是一个钩子方法,交给子类去实现
注意事项和细节
基本思想是:算法只存在于一个地方,也就是在父类中,容易修改。需要修改算法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改。
2) 实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接 使用。
3) 既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤的实现。
4) 该模式的不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加, 使得系统更加庞大
5) 一般模板方法都加上final关键字, 防止子类重写模板方法.
6) 模板方法模式使用场景:当要完成在某个过程,该过程要执行一系列步骤 ,这一 系列的步骤基本相同,但其个别步骤在实现时可能不同,通常考虑用模板方法模式来处理
相关文章:
<设计模式修炼>模板方法模式的使用场景和注意事项学习
介绍 模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。 2) 简单说ÿ…...

android 分享文件
1.在AndroidManifest.xml 中配置 FileProvider <providerandroid:name"android.support.v4.content.FileProvider"android:authorities"com.example.caliv.ffyy.fileProvider"android:exported"false"android:grantUriPermissions"true…...

UE5 C++(十一)— 碰撞检测
文章目录 代理绑定BeginOverlap和EndOverlapHit事件的代理绑定碰撞设置 代理绑定BeginOverlap和EndOverlap 首先,创建自定义ActorC类 MyCustomActor 添加碰撞组件 #include "Components/BoxComponent.h"public:UPROPERTY(VisibleAnywhere, BlueprintRea…...
时序数据库InfluxDB、TimeScaleDB简介
一、时序数据库作用、优点 1、作用: 时序数据库通常被用在监控场景,比如运维和 IOT(物联网)领域。这类数据库旨在存储时序数据并实时处理它们。 比如。我们可以写一个程序将服务器上 CPU 的使用情况每隔 10 秒钟向 InfluxDB 中…...

复试 || 就业day05(2024.01.08)项目一
文章目录 前言代码模拟梯度下降构建函数与导函数函数的可视化求这个方程的最小值(直接求导)求方程最小值(不令方程导为0)【梯度下降】eta0.1eta 0.2eta 50eta 0.01画出eta0.1时的梯度下降x的变化过程 总结 前言 💫你…...

基于商品列表的拖拽排序后端实现
目录 一:实现思路 二:实现步骤 二:实现代码 三:注意点 一:实现思路 后台实现拖拽排序通常需要与前端进行配合,对商品的列表拖拽排序,前端需要告诉后端拖拽的元素和拖动的位置。 这里我们假…...

小游戏实战丨基于PyGame的贪吃蛇小游戏
文章目录 写在前面PyGame贪吃蛇注意事项系列文章写在后面 写在前面 本期内容:基于pygame的贪吃蛇小游戏 下载地址:https://download.csdn.net/download/m0_68111267/88700188 实验环境 python3.11及以上pycharmpygame 安装pygame的命令:…...

AOP(面向切面编程)基于XML方式配置
概念解释:(理解基本概念方可快速入手) 连接点(joinpoint) 被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法。 切入点(pointcut&#x…...

多线程的概念
多线程 同时执行多个任务,例如一个人一边听歌,一边跳舞 继承Thread类实现多线程的方式 定义一个MyThread类继承Thread类,重写里面的run方法 package com.itxs.demo01;/*** Classname : MyThread* Description : TODO 自定义线程继承Thread类*…...

DeepPurpose 生物化学深度学习库;蛋白靶点小分子药物对接亲和力预测虚拟筛选
参考: https://blog.csdn.net/c9Yv2cf9I06K2A9E/article/details/107649770 https://github.com/kexinhuang12345/DeepPurpose ##安装 pip install DeepPurpose rdkitDeepPurpose包括: 数据: 关联TDC库下载,是同一作者开发的 https://blog.csdn.net/weixin_42357472/artic…...
Java实现责任链模式
责任链模式是一种设计模式,用于处理请求的解耦。在责任链模式中,多个对象都有机会处理请求,从而避免了请求发送者和接收者之间的直接依赖关系。每个处理者都可以决定是否处理请求以及将请求传递给下一个处理者。 简介 责任链模式由一条链组…...

rabbitmq延时队列相关配置
确保 RabbitMQ 的延时消息插件已经安装和启用。你可以通过执行以下命令来安装该插件: rabbitmq-plugins enable rabbitmq_delayed_message_exchange 如果提示未安装,以下是安装流程: 查看mq版本: 查看自己使用的 MQ(…...

【工具】推荐一个好用的代码画图工具
PlantUML 官网地址:https://plantuml.com/zh/ 跳转 支持各种结构化数据画图支持代码调用jar包生成图片 提供在线画图能力 https://www.plantuml.com/plantuml/uml/SyfFKj2rKt3CoKnELR1Io4ZDoSa70000 有兴趣可以尝试下 over~~...
Leetcode14-判断句子是否为全字母句(1832)
1、题目 全字母句 指包含英语字母表中每个字母至少一次的句子。 给你一个仅由小写英文字母组成的字符串 sentence ,请你判断 sentence 是否为 全字母句 。 如果是,返回 true ;否则,返回 false 。 示例 1: 输入&am…...

HTTP和TCP代理原理及实现,主要是理解
Web 代理是一种存在于网络中间的实体,提供各式各样的功能。现代网络系统中,Web 代理无处不在。我之前有关 HTTP 的博文中,多次提到了代理对 HTTP 请求及响应的影响。今天这篇文章,我打算谈谈 HTTP 代理本身的一些原理,…...
MySQL中的连接池
数据库的连接池 1 )概述 网站连接数据库,为庞大用户的每次请求创建一个连接是不合适的关闭并重新连接的成本是很大的处理方法:设置最大值, 最小值, 设置最多闲置连接,设置等待阻塞 2 )示例演示 import threading i…...
css计时器 animation实现计时器延时器
css计时器 animation实现计时器延时器 缺点当切页面导航会休眠不执行 最初需求是一个列表每个项目都有各自的失效时间 然后就想到 计时器延时器轮询等方案 这些方案每一个都要有自己的计时器 感觉不是很好 轮询也占资源 然后突发奇想 css能不能实现 开始想到的是transition测…...

【win11 绕过TPM CPU硬件限制安装】
Qt编程指南 VX:hao541022348 ■ 下载iso文件■ 右键文件点击装载出现如下问题■ 绕过TPM CPU硬件限制安装方法■ 虚拟机安装win11 ■ 下载iso文件 选择Windows11 (multi-edition ISO)在选择中文 ■ 右键文件点击装载出现如下问题 ■ 绕过T…...
k8s的yaml文件中的kind类型都有哪些?(清单版本)
在操作kubernetes的过程中,我们接触到的yaml文件中的kind类型有很多。他们代表了kubernetes的不同类型的对象,了解了kind的类型,也就相当于了解了k8s都有哪些类型的对象。 类型清单及概要说明 序号类型简述1Pod一个Kubernetes中最基本的资源…...
Jetpack Room使用
Room使用 回顾 数据库有多张表,一张表只能记录一种Class,Class的具体属性是这个表的列;所有对表的操作都要通过Dao来访问 注解说明: Enity 作用于Class上,表示创建一张表记录该Class,Class内部属性使用…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...

AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...

C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...