java干掉 if-else
前言 传统做法-if-else分支 策略模式+Map字典 责任链模式 策略模式+注解 物流行业中,通常会涉及到EDI报文(XML格式文件)传输和回执接收,每发送一份EDI报文,后续都会收到与之关联的回执(标识该数据在第三方系统中的流转状态)。
这里枚举几种回执类型:MT1101、MT2101、MT4101、MT8104、MT8105、MT9999,系统在收到不同的回执报文后,会执行对应的业务逻辑处理。当然,实际业务场景并没有那么笼统,这里以回执处理为演示案例
模拟一个回执类
@Data
public class Receipt {/*** 回执信息*/String message;/*** 回执类型(`MT1101、MT2101、MT4101、MT8104、MT8105、MT9999`)*/String type;}
模拟一个回执生成器
public class ReceiptBuilder {public static List<Receipt> generateReceiptList(){//直接模拟一堆回执对象List<Receipt> receiptList = new ArrayList<>();receiptList.add(new Receipt("我是MT2101回执喔","MT2101"));receiptList.add(new Receipt("我是MT1101回执喔","MT1101"));receiptList.add(new Receipt("我是MT8104回执喔","MT8104"));receiptList.add(new Receipt("我是MT9999回执喔","MT9999"));//......return receiptList;}
}
传统做法-if-else分支
List<Receipt> receiptList = ReceiptBuilder.generateReceiptList();
//循环处理
for (Receipt receipt : receiptList) {if (StringUtils.equals("MT2101",receipt.getType())) {System.out.println("接收到MT2101回执");System.out.println("解析回执内容");System.out.println("执行业务逻辑");} else if (StringUtils.equals("MT1101",receipt.getType())) {System.out.println("接收到MT1101回执");System.out.println("解析回执内容");System.out.println("执行业务逻辑");} else if (StringUtils.equals("MT8104",receipt.getType())) {System.out.println("接收到MT8104回执");System.out.println("解析回执内容");System.out.println("执行业务逻辑");} else if (StringUtils.equals("MT9999",receipt.getType())) {System.out.println("接收到MT9999回执");System.out.println("解析回执内容");System.out.println("执行业务逻辑");System.out.println("推送邮件");}// ......未来可能还有好多个else if
}
在遇到if-else的分支业务逻辑比较复杂时,我们都习惯于将其抽出一个方法或者封装成一个对象去调用,这样整个if-else结构就不会显得太臃肿。
就上面例子,当回执的类型越来越多时,分支else if 就会越来越多,每增加一个回执类型,就需要修改或添加if-else分支,违反了开闭原则(对扩展开放,对修改关闭)
我们知道, 策略模式的目的是封装一系列的算法,它们具有共性,可以相互替换,也就是说让算法独立于使用它的客户端而独立变化,客户端仅仅依赖于策略接口 。
在上述场景中,我们可以把if-else分支的业务逻辑抽取为各种策略,但是不可避免的是依然需要客户端写一些if-else进行策略选择的逻辑,我们可以将这段逻辑抽取到工厂类中去,这就是策略模式+简单工厂,代码如下
策略接口
/*** @Description: 回执处理策略接口* @Auther: wuzhazha*/
public interface IReceiptHandleStrategy {void handleReceipt(Receipt receipt);}
策略接口实现类,也就是具体的处理者
public class Mt2101ReceiptHandleStrategy implements IReceiptHandleStrategy {@Overridepublic void handleReceipt(Receipt receipt) {System.out.println("解析报文MT2101:" + receipt.getMessage());}}public class Mt1101ReceiptHandleStrategy implements IReceiptHandleStrategy {@Overridepublic void handleReceipt(Receipt receipt) {System.out.println("解析报文MT1101:" + receipt.getMessage());}}public class Mt8104ReceiptHandleStrategy implements IReceiptHandleStrategy {@Overridepublic void handleReceipt(Receipt receipt) {System.out.println("解析报文MT8104:" + receipt.getMessage());}}public class Mt9999ReceiptHandleStrategy implements IReceiptHandleStrategy {@Overridepublic void handleReceipt(Receipt receipt) {System.out.println("解析报文MT9999:" + receipt.getMessage());}}
策略上下文类(策略接口的持有者)
/*** @Description: 上下文类,持有策略接口* @Auther: wuzhazha*/
public class ReceiptStrategyContext {private IReceiptHandleStrategy receiptHandleStrategy;/*** 设置策略接口* @param receiptHandleStrategy*/public void setReceiptHandleStrategy(IReceiptHandleStrategy receiptHandleStrategy) {this.receiptHandleStrategy = receiptHandleStrategy;}public void handleReceipt(Receipt receipt){if (receiptHandleStrategy != null) {receiptHandleStrategy.handleReceipt(receipt);}}
}
策略工厂
/*** @Description: 策略工厂* @Auther: wuzhazha*/
public class ReceiptHandleStrategyFactory {private ReceiptHandleStrategyFactory(){}public static IReceiptHandleStrategy getReceiptHandleStrategy(String receiptType){IReceiptHandleStrategy receiptHandleStrategy = null;if (StringUtils.equals("MT2101",receiptType)) {receiptHandleStrategy = new Mt2101ReceiptHandleStrategy();} else if (StringUtils.equals("MT8104",receiptType)) {receiptHandleStrategy = new Mt8104ReceiptHandleStrategy();}return receiptHandleStrategy;}
}
客户端
public class Client {public static void main(String[] args) {//模拟回执List<Receipt> receiptList = ReceiptBuilder.generateReceiptList();//策略上下文ReceiptStrategyContext receiptStrategyContext = new ReceiptStrategyContext();for (Receipt receipt : receiptList) {//获取并设置策略IReceiptHandleStrategy receiptHandleStrategy = ReceiptHandleStrategyFactory.getReceiptHandleStrategy(receipt.getType());receiptStrategyContext.setReceiptHandleStrategy(receiptHandleStrategy);//执行策略receiptStrategyContext.handleReceipt(receipt);}}
}
解析报文MT2101:我是MT2101回执报文喔 解析报文MT8104:我是MT8104回执报文喔
由于我们的目的是消除if-else,那么这里需要将ReceiptHandleStrategyFactory策略工厂进行改造下,采用字典的方式存放我的策略,而Map具备key-value结构,采用Map是个不错选择。
稍微改造下,代码如下
/*** @Description: 策略工厂* @Auther: wuzhazha*/
public class ReceiptHandleStrategyFactory {private static Map<String,IReceiptHandleStrategy> receiptHandleStrategyMap;private ReceiptHandleStrategyFactory(){this.receiptHandleStrategyMap = new HashMap<>();this.receiptHandleStrategyMap.put("MT2101",new Mt2101ReceiptHandleStrategy());this.receiptHandleStrategyMap.put("MT8104",new Mt8104ReceiptHandleStrategy());}public static IReceiptHandleStrategy getReceiptHandleStrategy(String receiptType){return receiptHandleStrategyMap.get(receiptType);}
}
经过对策略模式+简单工厂方案的改造,我们已经消除了if-else的结构,每当新来了一种回执,只需要添加新的回执处理策略,并修改ReceiptHandleStrategyFactory中的Map集合。
如果要使得程序符合开闭原则,则需要调整ReceiptHandleStrategyFactory中处理策略的获取方式,通过反射的方式,获取指定包下的所有IReceiptHandleStrategy实现类,然后放到字典Map中去。
责任链模式
责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。
发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任
回执处理者接口
/*** @Description: 抽象回执处理者接口* @Auther: wuzhazha*/
public interface IReceiptHandler {void handleReceipt(Receipt receipt,IReceiptHandleChain handleChain);}
责任链接口/*** @Description: 责任链接口* @Auther: wuzhazha*/
public interface IReceiptHandleChain {void handleReceipt(Receipt receipt);
}
责任链接口实现类
/*** @Description: 责任链实现类* @Auther: wuzhazha*/
public class ReceiptHandleChain implements IReceiptHandleChain {//记录当前处理者位置private int index = 0;//处理者集合private static List<IReceiptHandler> receiptHandlerList;static {//从容器中获取处理器对象receiptHandlerList = ReceiptHandlerContainer.getReceiptHandlerList();}@Overridepublic void handleReceipt(Receipt receipt) {if (receiptHandlerList !=null && receiptHandlerList.size() > 0) {if (index != receiptHandlerList.size()) {IReceiptHandler receiptHandler = receiptHandlerList.get(index++);receiptHandler.handleReceipt(receipt,this);}}}
}
具体回执处理者public class Mt2101ReceiptHandler implements IReceiptHandler {@Overridepublic void handleReceipt(Receipt receipt, IReceiptHandleChain handleChain) {if (StringUtils.equals("MT2101",receipt.getType())) {System.out.println("解析报文MT2101:" + receipt.getMessage());}//处理不了该回执就往下传递else {handleChain.handleReceipt(receipt);}}
}public class Mt8104ReceiptHandler implements IReceiptHandler {@Overridepublic void handleReceipt(Receipt receipt, IReceiptHandleChain handleChain) {if (StringUtils.equals("MT8104",receipt.getType())) {System.out.println("解析报文MT8104:" + receipt.getMessage());}//处理不了该回执就往下传递else {handleChain.handleReceipt(receipt);}}
}
责任链处理者容器(如果采用spring,则可以通过依赖注入的方式获取到IReceiptHandler的子类对象)
/*** @Description: 处理者容器* @Auther: wuzhazha*/
public class ReceiptHandlerContainer {private ReceiptHandlerContainer(){}public static List<IReceiptHandler> getReceiptHandlerList(){List<IReceiptHandler> receiptHandlerList = new ArrayList<>();receiptHandlerList.add(new Mt2101ReceiptHandler());receiptHandlerList.add(new Mt8104ReceiptHandler());return receiptHandlerList;}}
客户端
public class Client {public static void main(String[] args) {//模拟回执List<Receipt> receiptList = ReceiptBuilder.generateReceiptList();for (Receipt receipt : receiptList) {//回执处理链对象ReceiptHandleChain receiptHandleChain = new ReceiptHandleChain();receiptHandleChain.handleReceipt(receipt);}}
}
解析报文MT2101:我是MT2101回执报文喔 解析报文MT8104:我是MT8104回执报文喔
通过责任链的处理方式,if-else结构也被我们消除了,每当新来了一种回执,只需要添加IReceiptHandler实现类并修改ReceiptHandlerContainer处理者容器即可,如果要使得程序符合开闭原则,则需要调整ReceiptHandlerContainer中处理者的获取方式,通过反射的方式,获取指定包下的所有IReceiptHandler实现类。
这里使用到了一个反射工具类,用于获取指定接口的所有实现类
/*** @Description: 反射工具类* @Auther: wuzhazha*/
public class ReflectionUtil {/*** 定义类集合(用于存放所有加载的类)*/private static final Set<Class<?>> CLASS_SET;static {//指定加载包路径CLASS_SET = getClassSet("com.yaolong");}/*** 获取类加载器* @return*/public static ClassLoader getClassLoader(){return Thread.currentThread().getContextClassLoader();}/*** 加载类* @param className 类全限定名称* @param isInitialized 是否在加载完成后执行静态代码块* @return*/public static Class<?> loadClass(String className,boolean isInitialized) {Class<?> cls;try {cls = Class.forName(className,isInitialized,getClassLoader());} catch (ClassNotFoundException e) {throw new RuntimeException(e);}return cls;}public static Class<?> loadClass(String className) {return loadClass(className,true);}/*** 获取指定包下所有类* @param packageName* @return*/public static Set<Class<?>> getClassSet(String packageName) {Set<Class<?>> classSet = new HashSet<>();try {Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".","/"));while (urls.hasMoreElements()) {URL url = urls.nextElement();if (url != null) {String protocol = url.getProtocol();if (protocol.equals("file")) {String packagePath = url.getPath().replace("%20","");addClass(classSet,packagePath,packageName);} else if (protocol.equals("jar")) {JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();if (jarURLConnection != null) {JarFile jarFile = jarURLConnection.getJarFile();if (jarFile != null) {Enumeration<JarEntry> jarEntries = jarFile.entries();while (jarEntries.hasMoreElements()) {JarEntry jarEntry = jarEntries.nextElement();String jarEntryName = jarEntry.getName();if (jarEntryName.endsWith(".class")) {String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");doAddClass(classSet,className);}}}}}}}} catch (IOException e) {throw new RuntimeException(e);}return classSet;}private static void doAddClass(Set<Class<?>> classSet, String className) {Class<?> cls = loadClass(className,false);classSet.add(cls);}private static void addClass(Set<Class<?>> classSet, String packagePath, String packageName) {final File[] files = new File(packagePath).listFiles(new FileFilter() {@Overridepublic boolean accept(File file) {return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();}});for (File file : files) {String fileName = file.getName();if (file.isFile()) {String className = fileName.substring(0, fileName.lastIndexOf("."));if (StringUtils.isNotEmpty(packageName)) {className = packageName + "." + className;}doAddClass(classSet,className);} else {String subPackagePath = fileName;if (StringUtils.isNotEmpty(packagePath)) {subPackagePath = packagePath + "/" + subPackagePath;}String subPackageName = fileName;if (StringUtils.isNotEmpty(packageName)) {subPackageName = packageName + "." + subPackageName;}addClass(classSet,subPackagePath,subPackageName);}}}public static Set<Class<?>> getClassSet() {return CLASS_SET;}/*** 获取应用包名下某父类(或接口)的所有子类(或实现类)* @param superClass* @return*/public static Set<Class<?>> getClassSetBySuper(Class<?> superClass) {Set<Class<?>> classSet = new HashSet<>();for (Class<?> cls : CLASS_SET) {if (superClass.isAssignableFrom(cls) && !superClass.equals(cls)) {classSet.add(cls);}}return classSet;}/*** 获取应用包名下带有某注解的类* @param annotationClass* @return*/public static Set<Class<?>> getClassSetByAnnotation(Class<? extends Annotation> annotationClass) {Set<Class<?>> classSet = new HashSet<>();for (Class<?> cls : CLASS_SET) {if (cls.isAnnotationPresent(annotationClass)) {classSet.add(cls);}}return classSet;}}
接下来改造ReceiptHandlerContainer
public class ReceiptHandlerContainer {private ReceiptHandlerContainer(){}public static List<IReceiptHandler> getReceiptHandlerList(){List<IReceiptHandler> receiptHandlerList = new ArrayList<>();//获取IReceiptHandler接口的实现类Set<Class<?>> classList = ReflectionUtil.getClassSetBySuper(IReceiptHandler.class);if (classList != null && classList.size() > 0) {for (Class<?> clazz : classList) {try {receiptHandlerList.add((IReceiptHandler)clazz.newInstance());} catch ( Exception e) {e.printStackTrace();}}}return receiptHandlerList;}}
至此,该方案完美符合了开闭原则,如果新增一个回执类型,只需要添加一个新的回执处理器即可,无需做其它改动。如新加了MT6666的回执,代码如下
public class Mt6666ReceiptHandler implements IReceiptHandler {@Overridepublic void handleReceipt(Receipt receipt, IReceiptHandleChain handleChain) {if (StringUtils.equals("MT6666",receipt.getType())) {System.out.println("解析报文MT6666:" + receipt.getMessage());}//处理不了该回执就往下传递else {handleChain.handleReceipt(receipt);}}
}
策略模式+注解
此方案其实和上述没有太大异同,为了能符合开闭原则,通过自定义注解的方式,标记处理者类,然后反射获取到该类集合,放到Map容器中,这里不再赘述
小结
if-else或switch case 这种分支判断的方式对于分支逻辑不多的简单业务,还是直观高效的。对于业务复杂,分支逻辑多,采用适当的模式技巧,会让代码更加清晰,容易维护,但同时类或方法数量也是倍增的。我们需要对业务做好充分分析,避免一上来就设计模式,避免过度设计!
相关文章:
java干掉 if-else
前言 传统做法-if-else分支 策略模式Map字典 责任链模式 策略模式注解 物流行业中,通常会涉及到EDI报文(XML格式文件)传输和回执接收,每发送一份EDI报文,后续都会收到与之关联的回执(标识该数据在第三方系统中的流转状态ÿ…...
29 Python的pandas模块
概述 在上一节,我们介绍了Python的numpy模块,包括:多维数组、数组索引、数组操作、数学函数、线性代数、随机数生成等内容。在这一节,我们将介绍Python的pandas模块。pandas模块是Python编程语言中用于数据处理和分析的强大模块&a…...
树叶识别系统python+Django网页界面+TensorFlow+算法模型+数据集+图像识别分类
一、介绍 树叶识别系统。使用Python作为主要编程语言开发,通过收集常见的6中树叶(‘广玉兰’, ‘杜鹃’, ‘梧桐’, ‘樟叶’, ‘芭蕉’, ‘银杏’)图片作为数据集,然后使用TensorFlow搭建ResNet50算法网络模型,通过对…...
【问题解决:配置】解决spring mvc项目 get请求 获取中文字符串参数 乱码
get类型请求的发送过程 前端发送一个get请求的过程: 封装参数进行URL编码,也就是将中文编码成一个带有百分号的字符串,具体可以在这个网站进行测试。http://www.esjson.com/urlEncode.html 进行Http编码,这里浏览器或者postman都…...
python每日一练(9)
🌈write in front🌈 🧸大家好,我是Aileen🧸.希望你看完之后,能对你有所帮助,不足请指正!共同学习交流. 🆔本文由Aileen_0v0🧸 原创 CSDN首发🐒 如…...
JVM第十四讲:调试排错 - Java 内存分析之堆内存和MetaSpace内存
调试排错 - Java 内存分析之堆内存和MetaSpace内存 本文是JVM第十四讲,以两个简单的例子(堆内存溢出和MetaSpace (元数据) 内存溢出)解释Java 内存溢出的分析过程。 文章目录 调试排错 - Java 内存分析之堆内存和MetaSpace内存1、常见的内存溢出问题(内存…...
【1day】泛微e-office OA SQL注入漏洞学习
注:该文章来自作者日常学习笔记,请勿利用文章内的相关技术从事非法测试,如因此产生的一切不良后果与作者无关。 目录 一、漏洞描述 二、影响版本 三、资产测绘 四、漏洞复现...
线上问题:所有用户页面无法打开
线上问题:所有用户页面无法打开 1 线上问题2 问题处理3 复盘3.1 第二天观察 1 线上问题 上午进入工作时间,Cat告警出现大量linda接口超时Exception。 随后,产品和运营反馈无法打开页面,前线用户大量反馈无法打开页面。 2 问题处…...
RabbitMQ和spring boot整合及其他内容
在现代分布式应用程序的设计中,消息队列系统是不可或缺的一部分,它为我们提供了解耦组件、实现异步通信和确保高性能的手段。RabbitMQ,作为一款强大的消息代理,能够协助我们实现这些目标。在本篇CSDN博客中,我们将探讨…...
iperf3交叉编译
简介 iperf3是一个用于执行网络吞吐量测量的命令行工具。它支持时序、缓冲区、协议(TCP,UDP,SCTP与IPv4和IPv6)有关的各种参数。对于每次测试,它都会详细的带宽报告,延迟抖动和数据包丢失。 如果是ubuntu系…...
TARJAN复习 求强连通分量、割点、桥
TARJAN复习 求强连通分量、割点、桥 文章目录 TARJAN复习 求强连通分量、割点、桥强连通分量缩点桥割点 感觉之前写的不好, 再水一篇博客 强连通分量 “有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有…...
python实现批量数据库数据插入
import pandas as pd import pymysql # 连接 MySQL 数据库 conn pymysql.connect( hostlocalhost, useryour_username, passwordyour_password, databaseyour_database_name, charsetutf8mb4, ) # 读取已有数据 existing_data pd.read_csv("86w全…...
python安装,并搞定环境配置和虚拟环境
鄙人使用Python来进行项目的开发,一般都是通过Anaconda来完成的。Anaconda不但封装了Python,还包含了创建虚拟环境的工具。 anaconda安装 安装anaconda,可以搜索清华镜像源,然后搜索anaconda,点击进入,然…...
Flink 的集群资源管理
集群资源管理 一、ResourceManager 概述 1、ResourceManager 作为统一的集群资源管理器,用于管理整个集群的计算资源,包括 CPU资源、内存资源等。 2、ResourceManager 负责向集群资源管理器申请容器资源启动TaskManager实例,并对TaskManag…...
STM32学习笔记
前言 今天开始学习STM32,公司封闭git网络,所以选择CSDN来同步学习进度,方便公司和家里都能更新学习笔记。 参考学习资料 江科大STM32教学视频: 江科大自动协STM32视频_哔哩哔哩_bilibili...
Java应用性能问题诊断技巧
作者:张彦东 参考:https://developer.aliyun.com/ebook/450?spma2c6h.20345107.ebook-index.28.6eb21f54J7SUYc 文章目录 (一)内存1.内存2.内存-JMX3.内存-Jmap4.内存-结合代码确认问题 (二)CPU1.CPU-JMX或…...
监控系列(六)prometheus监控DMHS操作步骤
一、监控的操作逻辑 给操作系统安装expect命令expect脚本执行dmhs_console脚本执行 cpt / exec 命令用脚本进行过滤字符串过滤dm_export读取脚本与当前日期作比较,然后返回差值 二、安装步骤 1. linux中Expect工具的安装及使用方法 https://blog.csdn.net/wangta…...
SLAM从入门到精通(dwa速度规划算法)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 要说搜路算法,这个大家都比较好理解。毕竟从一个地点走到另外一个地点,这个都是直觉上可以感受到的事情。但是这条道路上机…...
嵌入式实时操作系统的设计与开发(aCoral线程学习)
真正的RTOS,基本上没有做到进程,只是停留在多线程,因为多进程要解决很多问题,且需要硬件支持,这样就使得系统复杂了,从而就可能影响系统实时性。 线程之间是共享地址的,也就是说当前线程的地址…...
JAVA基础(JAVA SE)学习笔记(二)变量与运算符
前言 1. 学习视频: 尚硅谷Java零基础全套视频教程(宋红康2023版,java入门自学必备)_哔哩哔哩_bilibili 2023最新Java学习路线 - 哔哩哔哩 正文 第一阶段:Java基本语法 1. Java 语言概述 JAVA基础(JAVA SE)学习…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
快刀集(1): 一刀斩断视频片头广告
一刀流:用一个简单脚本,秒杀视频片头广告,还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农,平时写代码之余看看电影、补补片,是再正常不过的事。 电影嘛,要沉浸,…...
宇树科技,改名了!
提到国内具身智能和机器人领域的代表企业,那宇树科技(Unitree)必须名列其榜。 最近,宇树科技的一项新变动消息在业界引发了不少关注和讨论,即: 宇树向其合作伙伴发布了一封公司名称变更函称,因…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...
MySQL 主从同步异常处理
阅读原文:https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主,遇到的这个错误: Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一,通常表示ÿ…...
