java 设计模式之模板方法模式
简介
模板方法模式:定义一个算法的基本流程,将一些步骤延迟到子类中实现。模板方法模式可以提高代码的复用性,
模板方法中包含的角色:
- 抽象类:负责给出一个算法的基本流程,它由一个模板方法和若干个基本方法构成
- 模板方法:定义了算法的基本流程
- 基本方法:模板方法的具体步骤,基本方法是可以被抽象到父类中的公共方法,多个子类可以同时使用的方法就是基本方法
- 抽象方法:需要交给子类实现的方法,不同子类有着不同的实现
- 具体子类:实现抽象类中定义的抽象方法
适用场景:适合于算法的整体步骤是固定的,但是其中个别部分容易变化,不同子类有着不同实现。
模板方法模式的实现
案例:一个小demo,厨师炒菜,炒菜的顺序是不变的,不同厨师使用不同的菜
第一步:抽象类,在模板方法中定义整体流程
public abstract class AbstractTemplate {// 模板方法:厨师炒菜的基本流程public void cookProcess(){pourOil(); // 倒油heatOil(); // 热油pourVegetable(); // 放菜pourSauce(); // 放调料fry(); // 炒菜}// 基本方法private void pourOil(){System.out.println("倒油");}private void heatOil(){System.out.println("热油");}private void fry() {System.out.println("炒菜");}// 交给子类实现的抽象方法protected abstract void pourVegetable();protected abstract void pourSauce();
}
第二步:具体子类实现父类中的抽象方法
// 具体子类:厨师A
public class ConcreteClassBaoCai extends AbstractTemplate {private String name;public ConcreteClassBaoCai() { }public ConcreteClassBaoCai(String name) {this.name = name;}@Overridepublic void pourVegetable() {System.out.println(name + ": 下锅的蔬菜是包菜");}@Overridepublic void pourSauce() {System.out.println(name + ": 下锅的调料是辣椒");}
}// 具体子类:厨师B
public class ConcreteClassCaiXin extends AbstractTemplate {private String name;public ConcreteClassCaiXin() { }public ConcreteClassCaiXin(String name) {this.name = name;}@Overridepublic void pourVegetable() {System.out.println(name + ": 下锅的蔬菜是菜心");}@Overridepublic void pourSauce() {System.out.println(name + ": 下锅的调料是醋");}
}
测试:
public class Client {public static void main(String[] args) {ConcreteClassBaoCai classBaoCai = new ConcreteClassBaoCai("厨师A");classBaoCai.cookProcess();ConcreteClassCaiXin classCaiXin = new ConcreteClassCaiXin("厨师B");classCaiXin.cookProcess();}
}
使用案例
jdk中的juc包,里面就使用到了模板方法设计模式。具体来说,juc包中提供了一系列的锁工具,无论是什么类型的锁,它的共有流程都是获取锁成功后改变锁标志状态然后向下执行、获取锁失败后进入阻塞队列、锁释放后唤醒阻塞队列中的头结点,不同类型的锁,例如公平锁、非公平锁,它们是获取锁的方式不同,例如,公平锁如果发现阻塞队列中有值,会加入阻塞队列,非公平锁会直接获取锁,获取失败后才会加入阻塞队列,所以juc把锁相关的共有流程提取到了aqs中,把不同类型的锁独有的特性放到了具体的锁实现类中。接下来做一个详细介绍
1、juc中的模板方法:aqs中定义了获取锁的整体流程
public abstract class AbstractQueuedSynchronizerextends AbstractOwnableSynchronizerimplements java.io.Serializable {// 这就是一个模板方法,定义了获取锁的流程public final void acquire(int arg) {if (!tryAcquire(arg) && // 获取锁,成功后返回true,然后向下执行acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 获取锁失败,进入阻塞队列selfInterrupt();}// 交给子类实现的抽象方法,定义了获取锁的方式protected boolean tryAcquire(int arg) {// 这里的设计值得借鉴,在空方法中抛异常,避免外部误调用throw new UnsupportedOperationException();}// 父类中实现的具体方法,定义了获取锁失败后进入进入阻塞队列的方式,// 无论哪种类型的锁,进入阻塞队列的方式都是一样的final boolean acquireQueued(final Node node, int arg) {boolean failed = true;try {boolean interrupted = false;for (;;) {final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // help GCfailed = false;return interrupted;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())interrupted = true;}} finally {if (failed)cancelAcquire(node);}}
}
2、子类的具体实现
实现方式1:ReentrantLock中公平锁的实现方式
static final class FairSync extends Sync {private static final long serialVersionUID = -3000897897090466540L;final void lock() {acquire(1);}// 这里就是重写了上面父类中的tryAquire方法,定义了公平锁获取锁的方式protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) { // 锁没有被获取到if (!hasQueuedPredecessors() && // 队列中是否有元素compareAndSetState(0, acquires)) { // 如果没有,获取锁setExclusiveOwnerThread(current); // 获取锁成功后,当前线程设置为独占线程return true;}}else if (current == getExclusiveOwnerThread()) { // 如果当前线程已经获取到了锁int nextc = c + acquires; // 可重入的逻辑if (nextc < 0)throw new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}
}
实现方式2:ReentrantLock中非公平锁的实现方式
static final class NonfairSync extends Sync {// 这里重写了父类中的tryAcquire方法,定义了非公平锁的获取方式protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (compareAndSetState(0, acquires)) { // 如果锁没有被持有,直接尝试获取锁setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}
}
总结:这里顺便介绍了公平锁和非公平锁的实现,可以看出,唯一的区别在于,非公平锁在会直接尝试获取锁,公平锁会先判断阻塞队列中有没有元素,如果没有,再去获取锁,否则加入阻塞队列。
总结
模板方法设计模式,它的使用场景是,如果有多个类似的实体,它们有着共同的流程,每个实体又都有自己独特的地方,可以把它们相同的功能抽取出来,设计成一个模板方法,然后子类负责实现某些关键步骤,例如,之前的公平锁和非公平锁,它们获取锁的方式不同,但是获取锁失败后进入阻塞队列的方式是一样的。
相关文章:
java 设计模式之模板方法模式
简介 模板方法模式:定义一个算法的基本流程,将一些步骤延迟到子类中实现。模板方法模式可以提高代码的复用性, 模板方法中包含的角色: 抽象类:负责给出一个算法的基本流程,它由一个模板方法和若干个基本…...
基于大模型的腹股沟疝诊疗全流程风险预测与方案制定研究报告
目录 一、引言 1.1 研究背景与意义 1.2 国内外研究现状 1.3 研究目的与创新点 二、大模型技术概述 2.1 大模型基本原理 2.2 常用大模型类型及特点 2.3 大模型在医疗领域的应用潜力 三、腹股沟疝诊疗流程分析 3.1 腹股沟疝的发病机制与分类 3.2 传统术前评估方法与局…...
无约束最优化问题的求解算法--梯度下降法(Gradient Descent)
文章目录 梯度下降法梯度下降法原理(通俗版)梯度下降法公式学习率的设置**如何选择学习率?** 全局最优解梯度下降法流程损失函数的导函数三种梯度下降法**梯度下降法核心步骤回顾****优缺点详解****1. 全量梯度下降 (Batch Gradient Descent,…...
Python全功能PDF工具箱GUI:支持转换、加密、旋转、图片提取、日志记录等多功能操作
使用Python打造一款集成 PDF转换、编辑、加密、解密、图片提取、日志追踪 等多个功能于一体的桌面工具应用(Tkinter ttkbootstrap PyPDF2 等库)。 ✨项目背景与开发动机 在日常办公或学习中,我们经常会遇到各种关于PDF文件的操作需求&#…...
[密码学实战]国密算法面试题解析及应用
以下是密码学领域常见的面试题及其详细解析,涵盖基础理论、算法实现与应用场景,帮助系统化备战技术面试 一、基础概念类 1. 密码学的主要目标是什么? 答案: 确保数据的机密性(加密防止窃听)、完整性(哈希校验防篡改)、认证性(数字签名验证身份)和不可否认性(签名防…...
React 受控表单绑定基础
React 中最常见的几个需求是: 渲染一组列表绑定点击事件表单数据与组件状态之间的绑定 受控表单绑定是理解表单交互的关键之一。 📍什么是受控组件? 在 React 中,所谓“受控组件”,指的是表单元素(如 &l…...
计算机视觉---相机标定
相机标定在机器人系统中的作用 1.确定相机的内部参数 相机的内部参数包括焦距、主点坐标、像素尺寸等。这些参数决定了相机成像的几何关系。通过标定,可以精确获取这些参数,从而将图像中的像素坐标与实际的物理坐标建立联系。例如,已知相机…...
LeetCode 443 压缩字符串
字符数组压缩算法详解:实现与分析 一、引言 在处理字符数组时,我们常常遇到需要对连续重复字符进行压缩的场景。这不仅可以节省存储空间,还能提升数据传输效率。本文将深入解析一个经典的字符数组压缩算法,通过详细的实现步骤和…...
datasheet数据手册-阅读方法
DataSheet Datasheet(数据手册):电子元器件或者芯片的数据手册,一般由厂家编写,格式一般为PDF,内容为电子分立元器件或者芯片的各项参数,电性参数,物理参数,甚至制造材料…...
AI绘制流程图,方法概述
1 deepseek 生成图片的mermaid格式代码,在kimi中进行绘图或在jupter notebook中绘制: 或在draw.io中进行绘制(mermaid代码) 2 svg是矢量图,可以插入到word """mermaid graph TDA[基线解算] --> B[北…...
ObjectOutputStream 深度解析
ObjectOutputStream 深度解析 ObjectOutputStream 是 Java IO 体系中的一个关键类,用于序列化(将对象转换为字节流),通常与 ObjectInputStream 配合使用,实现对象的持久化存储或网络传输。 1.作用:完成对象的序列化过程 2.它可以将JVM当中的Java对象序列化到文件中/网…...
git回滚指定版本并操作
你可以通过以下步骤切换到第三个版本。根据你的需求,有两种主要方法: 方法 1:临时查看第三个版本(不修改当前分支) 适用于仅查看或测试旧版本,不保留后续修改: 找到第三个版本的提交哈希&#…...
【AI插件开发】Notepad++ AI插件开发实践:支持配置界面
一、引用 此前的系列文章已基本完成了Notepad的AI插件的功能开发,但是此前使用的配置为JSON配置文件,不支持界面配置。 本章在此基础上集成支持配置界面,这样不需要手工修改配置文件,直接在界面上操作,方便快捷。 注…...
polkitd服务无法启动导致docker无法启动问题解决
问题docker服务无法启动,溯源发现是polkit服务没有正确运行 systemctl status polkit可以看到类似提示 Sep 18 02:58:24 server1 dbus[897]: [system] Failed to activate service org.freedesktop.PolicyKit1: timed out Sep 18 02:59:29 server1 systemd[1]: po…...
软件工程中数据一致性的探讨
软件工程中数据一致性的探讨 引言数据一致性:软件工程中的业务正确性与性能的权衡数据一致性为何重要业务正确性:事务的原子性与一致性ACID原则的基石分布式事务的挑战一致性级别:从强一致到最终一致 实践中的一致性权衡金融系统:…...
数据库原理及应用mysql版陈业斌实验四
🏝️专栏:Mysql_猫咪-9527的博客-CSDN博客 🌅主页:猫咪-9527-CSDN博客 “欲穷千里目,更上一层楼。会当凌绝顶,一览众山小。” 目录 实验四索引与视图 1.实验数据如下 student 表(学生表&…...
华为OD机试真题——最长的顺子(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现
2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C、C语言、GO六种语言的最佳实现方式! 本文收录于专栏:《2025华为OD真题目录全流程解析/备考攻略/经验…...
【HTML】html文件
HTML文件全解析:搭建网页的基石 在互联网的广袤世界里,每一个绚丽多彩、功能各异的网页背后,都离不开HTML文件的默默支撑。HTML,即超文本标记语言(HyperText Markup Language),作为网页创建的基…...
使用 XWPFDocument 生成表格时固定列宽度
一、XWPFDocument XWPFTable个性化属性 1.初始默认写法 XWPFTable table document.createTable(n, m); //在文档中创建一个n行m列的表格 table.setWidth("100%"); // 表格占页面100%宽度// 通过getRow获取行进行自定义设置 XWPFTableRow row table.getRow(0); XW…...
足球AI模型:一款用数据分析赛事的模型
2023 年欧冠决赛前,某体育数据平台的 AI 模型以 78% 的概率预测曼城夺冠 —— 最终瓜迪奥拉的球队首次捧起大耳朵杯。当足球遇上 AI,那些看似玄学的 "足球是圆的",正在被数据与算法拆解成可计算的概率命题。今天我们就来聊聊&#…...
【ESP32|音频】一文读懂WAV音频文件格式【详解】
简介 最近在学习I2S音频相关内容,无可避免会涉及到关于音频格式的内容,所以刚开始接触的时候有点一头雾水,后面了解了下WAV相关内容,大致能够看懂wav音频格式是怎么样的了。本文主要为后面ESP32 I2S音频系列文章做铺垫࿰…...
万向死锁的发生
我是标题 1.欧拉角2.万向死锁 参考:小豆8593 1.欧拉角 欧拉角在Unity中描述的是一种变换(Transform)共有3个轴体,默认顺序为x->y->z. 2.万向死锁 可以把万向死锁的情况理解成:由于轴体旋转的顺序是固定的&am…...
JavaScript学习教程,从入门到精通,JavaScript BOM (Browser Object Model) 详解(18)
JavaScript BOM (Browser Object Model) 详解 1. BOM 介绍 BOM (Browser Object Model) 是浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象。BOM的核心对象是window,它表示浏览器的一个实例。 BOM包含的主要对象: window…...
人工智能与云计算:技术融合与实践
1. 引言 人工智能(AI)和云计算是当今科技领域最具变革性的两项技术。AI通过模拟人类智能解决问题,而云计算则提供了弹性可扩展的计算资源。两者的结合创造了前所未有的可能性,使企业能够以更低的成本部署复杂的AI解决方案。 本文将探讨AI与云计算的技术融合,包括核心概念、…...
42.[前端开发-JavaScript高级]Day07-手写apply-call-bind-块级作用域
手写apply-call-bind <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevi…...
ObjectInputStream 终极解析与记忆指南
ObjectInputStream 终极解析与记忆指南 一、核心本质 ObjectInputStream 是 Java 提供的对象反序列化流,继承自 InputStream,用于读取由ObjectOutputStream序列化的Java对象。 核心特性速查表 特性说明继承链InputStream → ObjectInputStream核心功能实现Java对象反序列化…...
数据结构有哪些类型(对于数据结构的简述)
在学习计算机时,数据结构是不可忽视的一点,从考研时的408课程,再到工作中编写软件,网站,要想在计算机领域站住脚跟,数据结构是必备的 在这里,我对于数据结构进行了汇总,并简要描述&…...
Vscode 插件开发
文章目录 1、使用vscode官方插件生成框架,下载脚手架2、使用脚手架初始化项目,这里我选择的是js3、生成的文件结构如下,重要的就是以下两个文件4、代码5、打包使用6、发布官网地址7、publisher ID undefined provided in the extension manif…...
C# string和其他引用类型的区别
在C#中,字符串(String)和其他引用类型(Reference Types)之间有几个关键的区别,这些区别主要体现在它们的内存管理、赋值行为以及使用方式上。 1. 内存管理 字符串(String)࿱…...
RTT添加一个RTC时钟驱动,以DS1307为例
添加一个外部时钟芯片 这里多了一个选项 复制drv_rtc.c,重命名为drv_rtc_ds1307.c 添加到工程中 /*** @file drv_rtc_ds1307.c* @brief * @author jiache (wanghuan3037@fiberhome.com)* @version 1.0* @date 2025-01-08* * @copyright Copyright (c) 2025 58* */ #...
