Java模板方法模式源码剖析及使用场景
一、原理与通俗理解
模板方法模式定义了一个算法的骨架,将某些步骤推迟到子类中实现。模板方法定义一个算法的骨架,将一些步骤的实现延迟到子类中完成。这样做的目的是确保算法的结构保持不变,同时又可以为不同的子类提供特定步骤的实现。
比如去餐馆吃饭,餐馆有固定的流程(下单->上菜->吃饭->付款),这就是模板方法。但对于不同的顾客,他们点的菜不同(重写了上菜这一步骤)。
二、案例演示
- 员工审核系统需求
- 收集员工信息
- 验证员工资格
- 核心决策是否雇佣
- 雇佣或拒绝员工
// 抽象类 - 模板方法
abstract class EmployeeApprover {// 模板方法public final void processRequest(EmployeeRequest request) {collectEmployeeInfo(request); // 1verifyEmployeeInfo(request); // 2if (approveEmployee(request)) { // 3hireEmployee(request); // 4} else {rejectEmployee(request); // 4}}// 收集员工信息 - 由子类实现protected abstract void collectEmployeeInfo(EmployeeRequest request);// 验证员工资格 - 由子类实现protected abstract void verifyEmployeeInfo(EmployeeRequest request);// 核心决策 - 由子类实现protected abstract boolean approveEmployee(EmployeeRequest request);// 具体雇佣步骤private void hireEmployee(EmployeeRequest request) {System.out.println("已雇佣员工: " + request.getName());}// 具体拒绝步骤private void rejectEmployee(EmployeeRequest request) {System.out.println("已拒绝员工: " + request.getName());}
}// 具体子类 - 实现抽象方法
class ITEmployeeApprover extends EmployeeApprover {@Overrideprotected void collectEmployeeInfo(EmployeeRequest request) {// 收集IT员工信息}@Overrideprotected void verifyEmployeeInfo(EmployeeRequest request) {// 验证IT员工资格}@Overrideprotected boolean approveEmployee(EmployeeRequest request) {// 审核IT员工是否合格return true;}
}
- CRM系统订单处理需求
- 收集订单信息
- 验证订单信息
- 核心决策是否发货
- 发货或拒绝订单
// 抽象类 - 模板方法
abstract class OrderProcessor {// 模板方法public final void processOrder(Order order) {collectOrderInfo(order); // 1verifyOrderInfo(order); // 2if (approveOrder(order)) { // 3shipOrder(order); // 4} else {rejectOrder(order); // 4}}// 收集订单信息 - 由子类实现protected abstract void collectOrderInfo(Order order);// 验证订单信息 - 由子类实现protected abstract void verifyOrderInfo(Order order);// 核心决策 - 由子类实现 protected abstract boolean approveOrder(Order order);// 具体发货步骤private void shipOrder(Order order) {System.out.println("已发货订单: " + order.getId());}// 具体拒绝步骤private void rejectOrder(Order order) {System.out.println("已拒绝订单: " + order.getId());}
}// 具体子类 - 实现抽象方法
class OnlineOrderProcessor extends OrderProcessor {@Overrideprotected void collectOrderInfo(Order order) {// 收集在线订单信息}@Overrideprotected void verifyOrderInfo(Order order) {// 验证在线订单信息}@Overrideprotected boolean approveOrder(Order order) {// 审核在线订单是否合格return true;}
}
三、Java源码中的模板方法模式
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 {// 模板方法}// 其他方法...
}
AbstractList抽象类
AbstractList提供了模板方法addAll()用于批量添加元素,而具体的添加逻辑由子类实现。
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {public boolean addAll(Collection<? extends E> c) {// 模板方法return batchOperation(c, true);}private boolean batchOperation(...) {// ...for (E e : c)result = add(e); // 调用抽象方法}public abstract boolean add(E e); // 抽象方法,子类实现
}
Spring JdbcTemplate
JdbcTemplate使用模板方法模式对底层的JDBC操作进行封装,开发者只需实现回调接口即可。以query方法为例:
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations { public <T> T query(String sql, Object[] args, ResultSetExtractor<T> rse) throws DataAccessException {// 模板方法return query(sql, newArgPreparedStatementSetter(args), rse);}// 实际的查询逻辑private <T> T query(PreparedStatementCreator psc, ResultSetExtractor<T> rse) throws DataAccessException {// 具体的数据库操作...rse.extractData(rs); // 调用回调接口}
}
四、总结优缺点以及使用经验
优点:
- 封装不变部分,扩展可变部分,代码复用性好
- 父类调用子类操作,通过子类扩展增强功能
- 符合开闭原则和里氏替换原则
缺点:
- 每个不同的实现都需要定义一个子类,类的个数可能过多
- 父类和子类之间存在潜在的扩展性限制
- 编写过程复杂,逻辑较难理解
使用经验:
- 适用于复杂流程,有固定不变的算法骨架和某些可变的细节
- 需要先分清楚算法固定部分和可变部分
- 体现了模板模式的核心思想"继承 + 多态"
- 在框架设计中是常用的模式,可以提高代码的复用性
- 不建议过度使用,需要权衡利弊,避免类膨胀
模板方法模式是一种典型的通过交换算法步骤扩展功能的设计模式,适用于算法骨架固定,某些步骤需要不同实现的场景。恰当使用可以提高代码复用性和系统扩展性。
相关文章:
Java模板方法模式源码剖析及使用场景
一、原理与通俗理解 模板方法模式定义了一个算法的骨架,将某些步骤推迟到子类中实现。模板方法定义一个算法的骨架,将一些步骤的实现延迟到子类中完成。这样做的目的是确保算法的结构保持不变,同时又可以为不同的子类提供特定步骤的实现。 比如去餐馆吃饭,餐馆有固定的流程(下…...
c++ 新的函数声明语法
右值引用(&&) 右值引用(&&)允许我们定义接受临时对象或移动语义的函数。 void foo(int&& x); // 右值引用参数默认参数 允许在函数声明中指定参数的默认值。 void bar(int x, double y 3.14); // 带有默认参数的函数声明noexcept关键字 指示函数…...
一款好用的AI工具——边界AICHAT
目录 一、简介二、注册及登录三、主要功能介绍3.1、模型介绍3.2、对话模型历史记录3.3、创作中心3.4、AI绘画SD3.5、文生图3.6、图生图3.7、线稿生图3.8、艺术二维码3.9、秀图广场3.10、AI绘画创作人像辅助器 一、简介 人工智能(AI)是一门研究、开发用于…...
谷歌承认“窃取”OpenAI模型关键信息
什么?谷歌成功偷家OpenAI,还窃取到了gpt-3.5-turbo关键信息??? 是的,你没看错。 根据谷歌自己的说法,它不仅还原了OpenAI大模型的整个投影矩阵(projection matrix)&…...
蓝桥杯(3.10)
1219. 移动距离 import java.util.Scanner; public class Main{public static void main(String[] args) {Scanner sc new Scanner(System.in);int w sc.nextInt();int m sc.nextInt();int n sc.nextInt();m--;n--;//由从1开始变为从0开始//求行号int x1 m/w, x2 n/w;//…...
Hololens 2应用开发系列(3)——MRTK基础知识及配置文件配置(中)
Hololens 2应用开发系列(3)——MRTK基础知识及配置文件配置(中) 一、前言二、输入系统2.1 MRTK输入系统介绍2.2 输入数据提供者(Input Data Providers)2.3 输入动作(Input Actions)2…...
吴恩达深度学习笔记:深度学习引言1.1-1.5
目录 第一门课:神经网络和深度学习 (Neural Networks and Deep Learning)第一周:深度学习引言(Introduction to Deep Learning)1.1 欢迎(Welcome)1.2 什么是神经网络?(What is a Neural Network)1.3 神经网络的监督学习(Supervised Learning …...
【Hadoop大数据技术】——Hadoop概述与搭建环境(学习笔记)
📖 前言:随着大数据时代的到来,大数据已经在金融、交通、物流等各个行业领域得到广泛应用。而Hadoop就是一个用于处理海量数据的框架,它既可以为海量数据提供可靠的存储;也可以为海量数据提供高效的处理。 目录 &#…...
蓝桥杯2023年第十四届省赛真题-工作时长
文件数据 把数据复制到excel中 数据按照增序排序 选中列数据,设置单元格格式,选择下述格式。注意,因为求和之后总小时数可能会超过24小时,所以不要选择最前面是hh的 设置B2 A2 - A1, B4 A4 - A3;然后选中已经算出…...
nginx禁止国外ip访问
1.安装geoip2扩展依赖 yum install libmaxminddb-devel -y 2.下载ngx_http_geoip2_module模块 https://github.com/leev/ngx_http_geoip2_module.git 3.编译安装 ./configure --add-module/datasdb/ngx_http_geoip2_module-3.4 4.下载最新数据库文件 模块安装成功后,还要…...
《腾讯音乐》24校招Java后端一面面经
1.手写LRU 2.项目拷打 3.Https客户端校验证书的细节? 4.对称加密和非对称加密的区别?你分别了解哪些算法? 5.在信息传输过程中,Https用的是对称加密还是非对称加密? 6.怎么防止下载的文件被劫持和篡改? 7.H…...
JavaScript:ES至今发展史简说
ECMAScript(简称ES)是JavaScript的标准,它的发展史经历了多个版本的迭代,以下是主要里程碑: ES1 (1997年6月):首个正式发布的ECMAScript标准,基于当时的JavaScript(由Netscape公司开…...
Linux:进程
进程 知识铺垫冯诺依曼体系结构操作系统(OS) 进程概念进程的查看ps 命令获取进程 pid文件内查看进程终止进程的方式kill命令快捷键 进程的创建 forkfork 返回值问题 进程状态运行状态 :R休眠状态:S (可中断)…...
【Vue3】defineExpose 实践
【Vue3】defineExpose 实践 defineExpose 是 Vue 3 的 <script setup> 语法糖中提供的一个函数,用于显式地暴露组件的属性、方法或其他响应式状态给其父组件或外部使用。这是在使用 <script setup> 语法时,控制组件公开哪些内部状态和方法的…...
centos7.9安装nacos
centos7.9安装nacos2.3.1 在centos x86_64环境安装nacos2.31环境准备 jdk1.8 、 mysql、 nacos 在window11环境安装nacos2.31 在centos x86_64环境安装nacos2.31 环境准备 jdk1.8 、 mysql、 nacos Nacos 依赖 Java 环境来运行。我们通过下载编译后压缩包方式安装。 重点踩坑…...
ARM/Linux嵌入式面经(四):浙江大华
大华一面 嵌入式 主要是问的项目相关 标准的十五分钟 电话面 这个面试官主要问项目,我同门面的全问八股,可能面试官不一样吧 文章目录 UART串口通信的波特率,常用波特率有哪些串口通信校验方式是什么,有什么区别方便简单的奇偶校验偶校验(even parity)累加和校验CRC循环冗…...
ubuntu 18.04安装教程(详细有效)
文章目录 一、下载ubuntu 18.04镜像二、安装ubuntu1. 点击下载好的Vmware Workstation,点击新建虚拟机,选择 “自定义(高级)”,之后下一步。2. 默认配置,不需要更改,点击下一步。3. 选择 “安装程序光盘映像文件(iso)(…...
第二十一天-NumPy
目录 什么是NumPy NumPy使用 1.数组的创建 2.类型转换 3.赠删改查 4.数组运算 5.矩阵运算 什么是NumPy 1.NumPy操作的是多维数组,什么是纬度? NumPy使用 1. 安装 pip install numpy import numpy as np 2.官网: 中文官网:…...
Vue:自动按需导入element-plus图标
自动导入使用 unplugin-icons 和 unplugin-auto-import 从 iconify 中自动导入任何图标集。 完整vite.config.js参考模板 https://download.csdn.net/download/ruancexiaoming/88928539 动态导入图标参考 https://blog.csdn.net/ruancexiaoming/article/details/136568219 导入…...
魔法之线:探索string类的神秘世界
🎉个人名片: 🐼作者简介:一名乐于分享在学习道路上收获的大二在校生 🙈个人主页🎉:GOTXX 🐼个人WeChat:ILXOXVJE 🐼本文由GOTXX原创,首发CSDN&…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...
永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...
