浅谈装饰模式
一、前言
hello大家好,本次打算简单聊一下装饰者模式,其实写有关设计模式的内容还是蛮有挑战性的,首先呢就是小永哥实力有限担心说不明白,其次设计模式是为了解决某些问题场景,在当前技术生态圈如此完善的情况下,能遇到使用设计模式的时候其实还是蛮少见的,而且我一直认为解决方案本身没有好坏之分,只有经过取舍适合当前的才是最好的。任何事物都是双刃剑,包括设计模式,在没有适合场景的情况下强行使用反而会造成过度设计,这样就不好了。
不过呢前几天小永哥确实遇到了一个小场景能用一下装饰者模式,不过作为演示呢我就不完整复刻那些复杂的代码了,咱来点简易的类比一下,尽量以少的代码能说明白。
二、业务场景
当时的业务场景是一个Excel导入功能,我们都知道导入时,需要读取逐行读取Excel数据,每行数据又要对应列的数据读取出来赋值给实体类对象,每一行就是一个实体类对象,最后将这些实体类对象设置到提前声明好的list集合中并调用批量保存完成导入,简易导入请看下述代码。
package com.relation;import com.alibaba.fastjson2.JSON;
import org.apache.poi.ss.usermodel.*;
import org.junit.jupiter.api.Test;import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;/*** @author huhy* @version 1.0* @Description:* @ClassName Date:2025/5/10 20:20*/
public class ImportTest {@Testpublic void test() throws IOException {ArrayList<Map<String,Object>> mapList = new ArrayList<>();// 导入的源文件String path = "E:\\test\\demo.xlsx";// 工作薄对象Workbook workbook = WorkbookFactory.create(new FileInputStream(path));// 工作表 sheetSheet sheet = workbook.getSheetAt(0);// 行int rows = sheet.getPhysicalNumberOfRows();DataFormatter dataFormatter = new DataFormatter();// 行的头信息,第一行,可以不处理for (int i = 1; i < rows; i++) {Row row = sheet.getRow(i);Map<String,Object> demoData = new HashMap<>();// 第一个单元格,因为是序号,可以不要// 从第二个单元格开始获取名称String name = dataFormatter.formatCellValue(row.getCell(1));demoData.put("name",name);// 第三个单元格获取编号String code = dataFormatter.formatCellValue(row.getCell(2));demoData.put("code",code);// 把组装好的 student对象,存入集合mapList.add(demoData);}System.out.println(JSON.toJSONString(mapList));}
}
以上就是一个简易的excel上传代码,运行测试类也能从excel中获取到数据,一个很正常和普通的小需求,想来以各位老铁的本事,这些都不叫事。下面有请我们T哥给我上点强度。
三、来自T哥的折磨
T哥:一般找我来都没啥好事,不过能给你填点堵我还是很乐意的。
小白:T哥你客气了,有事您吩咐,没有困难我制造困难也给你整明白儿的。
T哥:好了,废话少说,为了减少用户手输的错误率,你看能不能给表格内容去空格呀,防止用户不小心在前后多输空格然后又检查不出来。
小白:那太简单了,你就瞧好吧......
3.1、去空格需求的实现。
很简单嘛,给设置值的位置调用一下String自带的trim()方法不就好了,很轻松呀。
3.2、来自T哥的新需求。
T哥:这么快就实现了,不愧是专业的java开发人员,那个什么,客户要求除去空格之外,需要将每个数据都加上一个前缀AAA。这个能实现吧。
小白:好吧,也不是什么问题。
我们可以看到小白很快又搞定了,但是小白陷入了沉思。
小白:不对呀,为什么我每次都要改所有单元格设置的位置呢?我得想办法写个方法把这些集中起来,这样我只需要在第一次修改的时候改动位置稍微多一点,以后每次我修改集中起来的代码就好了。说干就干。
package com.relation;import com.alibaba.fastjson2.JSON;
import com.relation.common.utils.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.junit.jupiter.api.Test;import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;/*** @author huhy* @version 1.0* @Description:* @ClassName Date:2025/5/10 20:20*/
public class ImportTest {@Testpublic void test() throws IOException {// 将Excel文件导入到数据库中ArrayList<Map<String,Object>> mapList = new ArrayList<>();// 导入的源文件String path = "E:\\test\\demo.xlsx";// 工作薄对象Workbook workbook = WorkbookFactory.create(new FileInputStream(path));// 工作表 sheetSheet sheet = workbook.getSheetAt(0);// 行int rows = sheet.getPhysicalNumberOfRows();DataFormatter dataFormatter = new DataFormatter();// 行的头信息,第一行,可以不处理for (int i = 1; i < rows; i++) {Row row = sheet.getRow(i);Map<String,Object> demoData = new HashMap<>();// 第一个单元格,因为是序号,可以不要// 从第二个单元格开始获取名称String name = dataFormatter.formatCellValue(row.getCell(1));demoData.put("name",getStr(name));// 第三个单元格获取编号String code = dataFormatter.formatCellValue(row.getCell(2));demoData.put("code",getStr(code));// 把组装好的 student对象,存入集合mapList.add(demoData);}System.out.println(JSON.toJSONString(mapList));}private String getStr(String data){if(StringUtils.isEmpty(data)){return data;}return "AAA"+data.trim();}
}
小白抽取了一个方法,专门用来处理表格内容,好像比之前要好很多了。
T哥:你进步了,已经开始能自查并完善自己的代码了......
小白:当然了,每次都改那么多地方,我累,能少改干嘛要多改呢?
T哥:那既然你这么说,那你抽取getStr方法之后,不还是得在第一次修改的时候,逐个找到每个获取表格的位置去替换为使用getStr方法吗?
小白:还好吧,只有两处而已,有必要再折腾吗?
T哥:没错,现在确实是只有名称和编码两个属性,那万一有几十个属性呢?你也要一个个去修改吗?不是你自己说能少写一行代码就不多写一行吗?
小白:那好吧,我再想想办法,毕竟我是一个面向对象工程师......
3.3、面向对象方式改造
package com.relation;import com.relation.common.utils.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;/*** @author huhy* @version 1.0* @Description:* @ClassName Date:2025/5/10 21:47*/
public class DataFormatterExpand extends DataFormatter {@Overridepublic String formatCellValue(Cell cell) {String cellValue = super.formatCellValue(cell);if(StringUtils.isEmpty(cellValue)){return cellValue;}return "AAA"+cellValue.trim();}
}
package com.relation;import com.alibaba.fastjson2.JSON;
import com.relation.common.utils.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.junit.jupiter.api.Test;import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;/*** @author huhy* @version 1.0* @Description:* @ClassName Date:2025/5/10 20:20*/
public class ImportTest {@Testpublic void test() throws IOException {// 将Excel文件导入到数据库中ArrayList<Map<String,Object>> mapList = new ArrayList<>();// 导入的源文件String path = "E:\\test\\demo.xlsx";// 工作薄对象Workbook workbook = WorkbookFactory.create(new FileInputStream(path));// 工作表 sheetSheet sheet = workbook.getSheetAt(0);// 行int rows = sheet.getPhysicalNumberOfRows();DataFormatterExpand dataFormatter = new DataFormatterExpand();// 行的头信息,第一行,可以不处理for (int i = 1; i < rows; i++) {Row row = sheet.getRow(i);Map<String,Object> demoData = new HashMap<>();// 第一个单元格,因为是序号,可以不要// 从第二个单元格开始获取名称String name = dataFormatter.formatCellValue(row.getCell(1));demoData.put("name",name);// 第三个单元格获取编号String code = dataFormatter.formatCellValue(row.getCell(2));demoData.put("code",name);// 把组装好的 student对象,存入集合mapList.add(demoData);}System.out.println(JSON.toJSONString(mapList));}
}
我们可以看到,小白扩展了一个类并继承了DataFormatter并重写了formatCellValue方法,先调用父类的formatCellValue,然后再对获取的值进行统一扩展完成任务。
T哥:很好,一个非常标准的OO设计。
小白:当然了,我可是一个专业的OO程序员。
T哥:其实做到这一步已经设计的很不错了,代码改动也少,变化的代码也抽取出去了,那还有可以改进的地方吗?
小白:我不是很明白,现在不是很完美了吗?为什么还要改进?
T哥:如果针对此功能需求到此为止,那你的设计可以说完美,但是如果后续还有变化呢?你还能优雅保持你的扩展性吗?
小白:我想是可以的。
T哥:好的,那咱们继续,
3.4、T哥的BUFF叠加
T哥:来新需求了,我们需要再加上BBB后缀。
小白:这简单,我继续修改一下。
T哥:新需求来了,要求把AAA前缀去掉......
小白:T哥,你怕不是玩死我吧?
T哥:你说的什么话,不是你让我来给你提需求吗?
小白:我*******
T哥:我*******
然后T哥和小白打起来了.........
小永哥:小白你先放手,这事儿哥帮你办了,你先消消气。
3.5、小永哥的改造
package com.relation.expand;import com.relation.common.utils.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;/*** @author huhy* @version 1.0* @Description:* @ClassName Date:2025/5/10 21:47*/
public class DataFormatterTrimExpand extends DataFormatter {private DataFormatter dataFormatter;public void setDataFormatter(DataFormatter dataFormatter) {this.dataFormatter = dataFormatter;}@Overridepublic String formatCellValue(Cell cell) {String cellValue = dataFormatter.formatCellValue(cell);if(StringUtils.isEmpty(cellValue)){return cellValue;}return cellValue.trim();}
}
package com.relation.expand;import com.relation.common.utils.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;/*** @author huhy* @version 1.0* @Description:* @ClassName Date:2025/5/10 21:47*/
public class DataFormatterPrefixExpand extends DataFormatter {private DataFormatter dataFormatter;public void setDataFormatter(DataFormatter dataFormatter) {this.dataFormatter = dataFormatter;}@Overridepublic String formatCellValue(Cell cell) {String cellValue = dataFormatter.formatCellValue(cell);if(StringUtils.isEmpty(cellValue)){return cellValue;}return "AAA"+cellValue;}
}
package com.relation.expand;import com.relation.common.utils.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;/*** @author huhy* @version 1.0* @Description:* @ClassName Date:2025/5/10 21:47*/
public class DataFormatterSuffixExpand extends DataFormatter {private DataFormatter dataFormatter;public void setDataFormatter(DataFormatter dataFormatter) {this.dataFormatter = dataFormatter;}@Overridepublic String formatCellValue(Cell cell) {String cellValue = dataFormatter.formatCellValue(cell);if(StringUtils.isEmpty(cellValue)){return cellValue;}return cellValue+"BBB";}
}
package com.relation.expand;import org.apache.poi.ss.usermodel.DataFormatter;/*** @author huhy* @version 1.0* @Description:* @ClassName Date:2025/5/10 22:27*/
public class DataFormatterFactory {public static DataFormatter createDataFormatter(){DataFormatter dataFormatter = new DataFormatter();//创建去空格扩展类DataFormatterTrimExpand dataFormatterTrimExpand = new DataFormatterTrimExpand();//创建加前缀扩展类DataFormatterPrefixExpand dataFormatterPrefixExpand = new DataFormatterPrefixExpand();//创建加后缀扩展类DataFormatterSuffixExpand dataFormatterSuffixExpand = new DataFormatterSuffixExpand();//按需求进行组合//将原生DataFormatter设置到去空格扩展类来达到去空格功能dataFormatterTrimExpand.setDataFormatter(dataFormatter);//将去空格扩展类设置到加前缀扩展类,来给去空格后的值加前缀dataFormatterPrefixExpand.setDataFormatter(dataFormatterTrimExpand);//将加前缀扩展类设置到加后缀扩展类,给加完前缀值在加上后缀dataFormatterSuffixExpand.setDataFormatter(dataFormatterPrefixExpand);return dataFormatterSuffixExpand;}
}
package com.relation;import com.alibaba.fastjson2.JSON;
import com.relation.expand.DataFormatterFactory;
import com.relation.expand.DataFormatterTrimExpand;
import org.apache.poi.ss.usermodel.*;
import org.junit.jupiter.api.Test;import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;/*** @author huhy* @version 1.0* @Description:* @ClassName Date:2025/5/10 20:20*/
public class ImportTest {@Testpublic void test() throws IOException {// 将Excel文件导入到数据库中ArrayList<Map<String,Object>> mapList = new ArrayList<>();// 导入的源文件String path = "E:\\test\\demo.xlsx";// 工作薄对象Workbook workbook = WorkbookFactory.create(new FileInputStream(path));// 工作表 sheetSheet sheet = workbook.getSheetAt(0);// 行int rows = sheet.getPhysicalNumberOfRows();DataFormatter dataFormatter = DataFormatterFactory.createDataFormatter();// 行的头信息,第一行,可以不处理for (int i = 1; i < rows; i++) {Row row = sheet.getRow(i);Map<String,Object> demoData = new HashMap<>();// 第一个单元格,因为是序号,可以不要// 从第二个单元格开始获取名称String name = dataFormatter.formatCellValue(row.getCell(1));demoData.put("name",name);// 第三个单元格获取编号String code = dataFormatter.formatCellValue(row.getCell(2));demoData.put("code",code);// 把组装好的 student对象,存入集合mapList.add(demoData);}System.out.println(JSON.toJSONString(mapList));}
}
我们可以看到,经过小永哥的改造,前缀和后缀都加上了,但是好像代码量多了很多。
小白:永哥,你这是什么名堂,为啥你改造完以后代码量反而更多了呢?
小永哥:你说的对,初期确实代码量比你的OO设计要多了不少,待我给你好好介绍一下。
3.6、代码解析
1)、如下图所示,我们为每一种扩展都创建了对应的实现类。
2)、我们改造了扩展类,我们加了一个DataFormatter类型的成员变量,我们不再调用父类的方法,而是调用成员变量的方法。
3)、这样做的好处是,成员变量可以是原生的类,也可是我们的扩展类,这样的话,我们就可以按照需求灵活对扩展类进行组合。
4)、我们创建了一个简易的工厂DataFormatterFactory来生成DataFormatter,将我们组合的逻辑封装在工厂类的createDataFormatter方法中,从此刻开始,我们已经将所有变化的东西,从我们的主业务逻辑中抽取了出来。
5)、经过一系列的改造,我们的代码可扩展性和可维护性已经大大的提高了,需求变化时,如果我们已经有对应的扩展类,则直接进行组合即可,如果没有对应的扩展类,我们可以创建新的扩展类,并进行新的组合。
T哥:小永哥有两下子哈,小白你能总结一下你小永哥这么做符合哪些原则吗?
小白:首先,小永哥对每一种扩展创建对应的实现类,满足了单一职责。对于新的扩展,创建新的实现类,而不对业务代码进行修改,符合开闭原则,但好像对工厂类有改动,好像又没有很完美的符合开闭原则。
T哥:你说的很对,开闭原则是对修改关闭,对新增开放以大大减少对已有稳定代码的改动,以减少需求变化对系统的影响,但是要完全做到开闭原则很难,我们在开发过程中或多或少都会涉及到对原有代码的改动,这个是不可避免的,小永哥可以说将代码改动控制在很小范围之内了,如果出现问题,排查范围也会小很多。
小永哥:不好意思,我插一句哈,在扩展类的改造中,我使用了组合模式,利用组合模式松耦合的特性来提升系统的弹性,小白这一点你要牢记,有时候有一个比是一个要更好,说的更直白一点,就是组合模式要比继承的灵活性更强。
小白:永哥,我记住了。
3.7、总结
经过了一系列的改造,我们已经将代码改造好了,特别是最后一次改造,运用的就是经典的装饰模式。通过自由组合的方式对原始的类进行层层装饰,从而达到我们的目的。
四、结语
又耗费了不少脑细胞,写了这么多希望可以通过这个简单的案例将装饰模式能聊清楚,装饰模式虽然很经典,但是在小永哥的心中,威力最大的还是策略模式,特别是策略模式+模版方法模式,威力巨大,能灵活多变的应对繁琐的业务变化,小永哥好好构思一下业务场景,争取下把和大家聊聊这两种设计模式以及这两种设计模式的组合体,本次就到这了,谢谢大家,晚安。
相关文章:

浅谈装饰模式
一、前言 hello大家好,本次打算简单聊一下装饰者模式,其实写有关设计模式的内容还是蛮有挑战性的,首先呢就是小永哥实力有限担心说不明白,其次设计模式是为了解决某些问题场景,在当前技术生态圈如此完善的情况下&#…...

LeetCode 270:在二叉搜索树中寻找最接近的值(Swift 实战解析)
文章目录 摘要描述题解答案题解代码分析示例测试及结果时间复杂度空间复杂度总结 摘要 在日常开发中,我们经常需要在一组有序的数据中快速找到最接近某个目标值的元素。LeetCode 第 270 题“Closest Binary Search Tree Value”正是这样一个问题。本文将深入解析该…...

WPF 3D图形编程核心技术解析
一、三维坐标系系统 WPF采用右手坐标系系统,空间定位遵循: X 轴 → 右 Y 轴 → 上 Z 轴 → 观察方向 X轴 \rightarrow 右\quad Y轴 \rightarrow 上\quad Z轴 \rightarrow 观察方向 X轴→右Y轴→上Z轴→观察方向 三维坐标值表示为 ( x , y , z ) (x, y,…...
分布式锁原理
1.锁是什么 一个线程拿到锁,另一个线程就拿不到,满足互斥性。 2.Redis的setnx实现 加锁后解锁,但是要先判断是否是当前线程持有的锁,只能释放本线程的锁。 先判断后释放,两步操作Lua实现原子性 3.为什么要给锁加过期…...

暗物质卯引力挂载技术
1、物体质量以及其所受到的引力约束(暗物质压力差) 自然界的所有物体,其本身都是没有质量的。我们所理解的质量,其实是物体球周空间的暗物质对物体的挤压,压力差。 对于宇宙空间中的单个星球而言,它的球周各处压力是相同的,所以,它处于平衡状态,漂浮在宇宙中。 对于星…...
实现三个采集板数据传送到一个显示屏的方案
实现三个采集板数据传送到一个显示屏的方案 要实现三个相同采集板的数据都传送到一个显示屏上,可行的方案: 方案:串行通信(推荐) 硬件连接: 使用RS485总线连接(适合较长距离)或使用…...

comfyui 如何优雅的从Hugging Face 下载模型,文件夹
如下图所示 使用git 下载整个仓库然后把需要的放到对应的位置...

通过user-agent来源判断阻止爬虫访问网站,并防止生成[ error ] NULL日志
一、TP5.0通过行为(Behavior)拦截爬虫并避免生成 [ error ] NULL 错误日志 1. 创建行为类(拦截爬虫) 在 application/common/behavior 目录下新建BlockBot.php ,用于识别并拦截爬虫请求: <?php name…...
动态规划法:爬楼梯
假如你现在爬楼梯,需要n阶才能到达楼顶,每次可以爬1或2 台阶,你有多少中不同的方法可以爬到楼顶。 例如: 输入:n2 输出:2 //有两种方法可以到达楼顶,1阶1阶,2阶。 输入&…...

IBM BAW(原BPM升级版)使用教程第七讲
续前篇! 一、团队 在 IBM Business Automation Workflow (BAW) 中,团队(Team) 是流程管理的关键部分,用于定义参与某个流程的用户、角色、组以及服务等。在团队配置中,有许多重要概念,特别是 …...

【论文阅读】Efficient and secure federated learning against backdoor attacks
Efficient and secure federated learning against backdoor attacks -- 高效且安全的可抵御后门攻击的联邦学习 论文来源问题背景TLDR系统及威胁模型实体威胁模型 方法展开服务器初始化本地更新本地压缩高斯噪声与自适应扰动聚合与解压缩总体算法 总结优点缺点 论文来源 名称…...

Java中的代理机制
目录 什么叫代理 静态代理 优缺点 优点: 缺点: 动态代理 JDK动态代理 核心类 JDK动态代理的实现 步骤 示例 特点 CGLIB动态代理 代理机制对比 总结 什么叫代理 代理模式是一种比较好理解的设计模式。简单来说就是我们使用代理对象来代替…...
Kotlin扩展函数提升Android开发效率
在Android开发中,Kotlin的扩展函数(Extension Functions)犹如一把神奇的瑞士军刀,它能显著提升代码简洁性和开发效率。以下是通过实战案例展示的扩展函数魔法手册: 一、扩展函数基础原理 // 给View添加渐显动画扩展 f…...

Jenkins linux安装
jenkins启动 service jenkins start 重启 service jenkins restart 停止 service jenkins stop jenkins安装 命令切换到自己的下载目录 直接用命令下载 wget http://pkg.jenkins-ci.org/redhat-stable/jenkins-2.190.3-1.1.noarch.rpm 下载直接安装 rpm -ivh jenkins-2.190.3-…...
加速pip下载:永久解决网络慢问题
一文教你解决 pip 下载太慢了的问题 || 下载时因为网络不好中断下载的问题 一、找到 pip 配置文件路径 1.配置文件位置: Windows 系统的 pip 配置文件默认不存在,需要手动创建,路径为: C:\Users\你的用户名\pip\pip.ini 用户目…...
WPF 触发器 Trigger
触发器 Trigger 触发器(Trigger)是 WPF 中的一种机制: 当某个条件满足时,自动改变控件的某些属性,比如颜色、大小、透明度等。 换句话说,就是"如果……那么就……" 的一种规则。 常见触发器类…...

Webug4.0靶场通关笔记-靶场搭建方法(3种方法)
目录 一、虚拟机绿色版本 1. 开启phpstudy 2. 访问靶场 二、Docker版本 1.拉取镜像 2.启动镜像 三、源码安装版本 1. 搭建环境 (1)安装PHPStudy (2)WeBug4.0靶场源码 (3)安装Navicat ÿ…...
Python核心编程深度解析:作用域、递归与匿名函数的工程实践
引言 Python作为现代编程语言的代表,其作用域管理、递归算法和匿名函数机制是构建高质量代码的核心要素。本文基于Python 3.11环境,结合工业级开发实践,深入探讨变量作用域的内在逻辑、递归算法的优化策略以及匿名函数的高效应用,…...

【Web】LACTF 2025 wp
目录 arclbroth lucky-flag whack-a-mole arclbroth 看到username为admin能拿到flag 但不能重复注册存在的用户 这题是secure-sqlite这个库的问题,底层用的是C,没处理好\0字符截断的问题 (在 Node.js 中,由于其字符串表示方式…...

【日撸 Java 三百行】综合任务 1
目录 Day 10:综合任务 1 一、题目分析 1. 数据结构 2. 相关函数基本知识 二、模块介绍 1. 初始化与成绩矩阵的构建 2. 创建总成绩数组 3. 寻找成绩极值 三、代码与测试 小结 拓展:关于求极值的相关算法 Day 10:综合任务 1 Task&…...
yocto的每个recipe都是在工作路径中完成
Yocto项目中每个Recipe的编译过程都会将源文件解压或搬运到tmp/work/下的特定工作目录,并在此完成所有构建任务。具体流程可分为以下关键步骤: 一、源码处理阶段 源码获取(do_fetch) Recipe通过SRC_URI变量指定源码来源(如Git仓库、HTTP下载或本地文件)。这些文件会被下载…...
玩转Docker | 使用Docker部署DailyTxT日记工具
玩转Docker | 使用Docker部署DailyTxT日记工具 一、DailyTxT介绍DailyTxT简介DailyTxT 特点二、系统要求环境要求环境检查Docker版本检查检查操作系统版本三、部署DailyTxT服务下载DailyTxT镜像编辑部署文件创建容器检查容器状态检查服务端口安全设置四、访问DailyTxT服务访问D…...
初等数论--欧拉定理及证明
0. 证明前置知识 同余类(剩余类) r n ‾ { x ∣ x m n r , m ∈ Z } \overline{r_n} \{ x| xmnr,m \in Z\} rn{x∣xmnr,m∈Z} r n ‾ \overline{r_n} rn表示模 n n n后余 r r r的同余类(剩余类) 比如 2 5 ‾ { ⋯…...
Oracle非归档模式遇到文件损坏怎么办?
昨天夜里基地夜班的兄弟,打电话说有个报表库连不上了,赶紧起来连上VPN查看一下,看到实例宕机了,先赶紧startup起来。 1.查看报错信息 环境介绍:Redhat 6.9 Oracle 11.2.0.4 No Archive Mode 查看alert log 关键报…...
机器人领域和心理学领域 恐怖谷 是什么
机器人领域和心理学领域 恐怖谷 是什么 恐怖谷是一个在机器人领域和心理学领域备受关注的概念,由日本机器人专家森政弘于1970年提出。 含义 当机器人与人类的相似度达到一定程度时,人类对它们的情感反应会突然从积极变为消极,产生一种毛骨悚然、厌恶恐惧的感觉。这种情感…...
树莓派4的v4l2摄像头(csi)no cameras available,完美解决
根据2025年最新技术文档和树莓派官方支持建议,no cameras available错误通常由驱动配置冲突或硬件连接问题导致。以下是系统化解决方案: 一、核心修复步骤 强制禁用传统驱动 sudo nano /boot/firmware/config.txt确保包含以下配置(2025年新版…...
每日一题:两个仓库的最低配送费用问题
文章目录 两个仓库的最低配送费用问题一、问题描述二、解题思路(一)初始假设(二)差值定义(三)选择最优(四)计算答案 三、代码实现四、代码分析(一)输入处理&a…...

华为私有协议Hybrid
实验top图 理论环节 1. 基本概念 Hybrid接口: 支持同时处理多个VLAN流量,且能针对不同VLAN配置是否携带标签(Tagged/Untagged)。 核心特性: 灵活控制数据帧的标签处理方式,适用于复杂网络场景。 2. 工作…...
Redis 基本数据类型解析
Redis 是一个高效的内存数据存储系统,广泛应用于缓存、消息队列、排行榜、实时数据处理等场景。其高性能的特点部分源自其丰富的数据结构,Redis 提供了多种数据类型,能够支持不同的使用需求。本文将详细介绍 Redis 的八种基本数据类型。 1. …...

数据库实验10
设计性实验 1.实验要求 1.编写函数FsumXXX,1~n(参数)求和; GO CREATE FUNCTION Fsum065 (n INT) RETURNS INT AS BEGIN DECLARE sum INT 0 WHILE n > 0 BEGIN SET sum sum n SET n n - 1 END RETURN sum END …...