当前位置: 首页 > news >正文

01 设计模式-创造型模式-工厂模式

  • 工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一,它提供了一种创建对象的方式,使得创建对象的过程与使用对象的过程分离。

  • 工厂模式提供了一种创建对象的方式,而无需指定要创建的具体类。

  • 通过使用工厂模式,可以将对象的创建逻辑封装在一个工厂类中,而不是在客户端代码中直接实例化对象,这样可以提高代码的可维护性和可扩展性。

设计模式,最近持续更新中,如需要请关注

如果你觉得我分享的内容或者我的努力对你有帮助,或者你只是想表达对我的支持和鼓励,请考虑给我点赞、评论、收藏。您的鼓励是我前进的动力,让我感到非常感激。

文章目录

  • 1 概要
  • 2 实现
  • 3 Demo代码
  • 4 开发案例
    • 4.1 算法执行服务里,不同的任务数据来源不同,执行脚本类型不同,结果处理不同,使用工厂模式
    • 4.2 网络还原时,不同的采集数据,解析处理方式不同

1 概要

意图
定义一个创建对象的接口,让其子类决定实例化哪一个具体的类。工厂模式使对象的创建过程延迟到子类。

主要解决
接口选择的问题。

何时使用
当我们需要在不同条件下创建不同实例时。

如何解决
通过让子类实现工厂接口,返回一个抽象的产品。

关键代码
对象的创建过程在子类中实现。

应用实例

  1. 汽车制造:你需要一辆汽车,只需从工厂提货,而不需要关心汽车的制造过程及其内部实现。
  2. Hibernate:更换数据库时,只需更改方言(Dialect)和数据库驱动(Driver),即可实现对不同数据库的切换。

优点

  1. 调用者只需要知道对象的名称即可创建对象。
  2. 扩展性高,如果需要增加新产品,只需扩展一个工厂类即可。
  3. 屏蔽了产品的具体实现,调用者只关心产品的接口。

缺点
每次增加一个产品时,都需要增加一个具体类和对应的工厂,使系统中类的数量成倍增加,增加了系统的复杂度和具体类的依赖。

使用场景

  1. 日志记录:日志可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志的位置。
  2. 数据库访问:当用户不知道最终系统使用哪种数据库,或者数据库可能变化时。
  3. 连接服务器的框架设计:需要支持 “POP3”、“IMAP”、“HTTP” 三种协议,可以将这三种协议作为产品类,共同实现一个接口。
  4. 在算法执行服务中,每个任务需要处理的数据来源不同,根据数据类型创建对应的数据出来handle类,不用关心handle里的内部处理逻辑

注意事项
工厂模式适用于生成复杂对象的场景。如果对象较为简单,通过 new 即可完成创建,则不必使用工厂模式。使用工厂模式会引入一个工厂类,增加系统复杂度。

结构
工厂模式包含以下几个主要角色:

  • 抽象产品(Abstract Product):定义了产品的共同接口或抽象类。它可以是具体产品类的父类或接口,规定了产品对象的共同方法。
  • 具体产品(Concrete Product):实现了抽象产品接口,定义了具体产品的特定行为和属性。
  • 抽象工厂(Abstract Factory):声明了创建产品的抽象方法,可以是接口或抽象类。它可以有多个方法用于创建不同类型的产品。
  • 具体工厂(Concrete Factory):实现了抽象工厂接口,负责实际创建具体产品的对象。

2 实现

我们将创建一个 Shape 接口和实现 Shape 接口的实体类。下一步是定义工厂类 ShapeFactory。

FactoryPatternDemo 类使用 ShapeFactory 来获取 Shape 对象。它将向 ShapeFactory 传递信息(CIRCLE / RECTANGLE / SQUARE),以便获取它所需对象的类型。
请添加图片描述

3 Demo代码

在这里插入图片描述
Shape

/*** 公共接口*/
public interface Shape {void draw();
}

Circle

/*** 圆形,形状的实现类*/
public class Circle implements Shape {@Overridepublic void draw() {System.out.println("Inside Circle::draw() method.");}
}

Rectangle

/*** 矩形,形状的实现类*/
public class Rectangle implements Shape {@Overridepublic void draw() {System.out.println("Inside Rectangle::draw() method.");}
}

Square

/*** 方形,形状的实现类*/
public class Square implements Shape {@Overridepublic void draw() {System.out.println("Inside Square::draw() method.");}
}

ShapeFactory

/*** 形状工厂类【根据不同的参数创建对应的实例】*/
public class ShapeFactory {//使用 getShape 方法获取形状类型的对象public Shape getShape(String shapeType) {if (shapeType == null) {return null;}if (shapeType.equalsIgnoreCase("CIRCLE")) {return new Circle();} else if (shapeType.equalsIgnoreCase("RECTANGLE")) {return new Rectangle();} else if (shapeType.equalsIgnoreCase("SQUARE")) {return new Square();}return null;}
}

FactoryPatternDemo

/***    总结:用来根据不同的参数创建对象*/
public class FactoryPatternDemo {public static void main(String[] args) {ShapeFactory shapeFactory = new ShapeFactory();//获取 Circle 的对象,并调用它的 draw 方法Shape shape1 = shapeFactory.getShape("CIRCLE");//调用 Circle 的 draw 方法shape1.draw();//获取 Rectangle 的对象,并调用它的 draw 方法Shape shape2 = shapeFactory.getShape("RECTANGLE");//调用 Rectangle 的 draw 方法shape2.draw();//获取 Square 的对象,并调用它的 draw 方法Shape shape3 = shapeFactory.getShape("SQUARE");//调用 Square 的 draw 方法shape3.draw();}
}

效果
在这里插入图片描述

4 开发案例

4.1 算法执行服务里,不同的任务数据来源不同,执行脚本类型不同,结果处理不同,使用工厂模式

请添加图片描述
说明:

  • TaskAbstractFactory命名成抽象工厂,可以创建出来DataSetHandle工厂,ScriptExecuteHandle工厂,ResultHandle工厂,但是实现时,时间关系,简化成简单工厂模式。
  • 工厂返回的对象,每次都是新创建出来的,因为这些handle每次创建初始化的参数是不同的,和下面的第二个案例有所不同

在这里插入图片描述

工厂类

/*** 任务抽象工厂类,创建各种处理类* @since 2023 -10-08 16:13*/
public class TaskAbstractFactory {private static final Logger LOGGER = LoggerFactory.getLogger(TaskAbstractFactory.class);/*** Gets script execute handle.** @param scriptParam the script param* @param algoId the algo id* @return the script execute handle*/public static ScriptExecuteHandle getScriptExecuteHandle(ScriptParam scriptParam, String algoId) {if (Constants.ScriptType.PYTHON.equals(scriptParam.getScriptType()) || Constants.ScriptType.PYTHON3.equals(scriptParam.getScriptType())) {return new PythonScriptExecuteHandle(scriptParam);} else {LOGGER.error("The algorithm type is not supported. algoId: {} ,scriptType: {} ", algoId,scriptParam.getScriptType());throw new CommonServiceException(AIModelError.ALGO_TYPE_NOT_SUPPORTED);}}/*** Gets data set handle list.** @param dataSets the data sets* @return the data set handle list*/public static List<DataSetHandle> getDataSetHandleList(List<InputDataSource> dataSets) {ArrayList<DataSetHandle> dataSetHandleList = new ArrayList<>(10);for (InputDataSource inputDataSource : dataSets) {dataSetHandleList.add(getDataSetHandle(inputDataSource));}return dataSetHandleList;}/*** Gets data set handle.** @param inputDataSource the input data source* @return the data set handle*/public static DataSetHandle getDataSetHandle(InputDataSource inputDataSource) {if (Constants.DataSourceType.MINIO_FILE.equalsIgnoreCase(inputDataSource.getDatatype())) {DataSetHandle dataSetHandle = new S3DataSetHandle(inputDataSource.getDataSourceInfo(),inputDataSource.getDataSourceConfig());// 进行数据源校验dataSetHandle.checkDataSource();return dataSetHandle;} else if (Constants.DataSourceType.HDFS_FILE.equalsIgnoreCase(inputDataSource.getDatatype())) {DataSetHandle dataSetHandle = new HdfsDataSetHandle(inputDataSource.getDataSourceInfo(),inputDataSource.getDataSourceConfig());// 进行数据源校验dataSetHandle.checkDataSource();return dataSetHandle;} else {LOGGER.error("The data source type is not supported. datatype: {} ", inputDataSource.getDatatype());throw new CommonServiceException(AIModelError.DATA_TYPE_NOT_SUPPORTED);}}/*** Gets result handle.** @param calculateParam the calculate param* @param scriptParam the script param* @return the result handle*/public static ResultHandle getResultHandle(CalculateParam calculateParam, ScriptParam scriptParam) {// 【预留】 设置结果集存放的数据源。目前所有的算法都有数据集,取数据集的第一个数据源作为结果上传的数据源OutputDataSource outputDataSource = getOutDataSource(calculateParam.getDataSets().get(0));if (Constants.CustomizedAlgoId.POTENTIAL_GUEST_ALGO_ID.equals(calculateParam.getAlgoId())) {// 定制化的处理方式,需要走特有的处理方式。此类算法,只能提前预置后return new PotentialGuestResultHandle(scriptParam, outputDataSource);} else {// 任务结果走默认处理方式,此类算法可以通过算法管理界面可以添加return new ResultHandle(scriptParam, outputDataSource);}}private static OutputDataSource getOutDataSource(InputDataSource inputDataSource) {return new OutputDataSource(inputDataSource.getDatatype(), inputDataSource.getDataSourceConfig());}}

使用

    public TaskEntity(TaskInfo taskInfo, CalculateParam calculateParam, String algoPackDir, String localFileDir) {this.scriptParam = getScriptParam(calculateParam, algoPackDir, localFileDir);this.taskInfo = taskInfo;this.shellParamHandle = TaskAbstractFactory.getScriptExecuteHandle(scriptParam, calculateParam.getAlgoId());this.dataSetHandleList = TaskAbstractFactory.getDataSetHandleList(calculateParam.getDataSets());this.resultHandle = TaskAbstractFactory.getResultHandle(calculateParam, scriptParam);}

其他说明
设计是工厂创建实例的是子类,返回的是父类。多态的体现。同事父类有默认方法,子类是对父类的扩展, 或者重写。如下:
DataSetHandle

/*** 数据集处理父类* @since 2023 -09-15 15:35*/
public abstract class DataSetHandle {private static final Logger LOGGER = LoggerFactory.getLogger(DataSetHandle.class);/*** The Data source info.*/protected String dataSourceInfo;/*** The Data source config.*/protected String dataSourceConfig;/*** Instantiates a new Data set handle.** @param dataSourceInfo the data source info* @param dataSourceConfig the data source config*/public DataSetHandle(String dataSourceInfo, String dataSourceConfig) {this.dataSourceInfo = dataSourceInfo;this.dataSourceConfig = dataSourceConfig;}/*** Check data source.*/public void checkDataSource() {// 对参数的json格式进行校验if (!MyStringUtil.checkJson(dataSourceInfo)) {LOGGER.error("dataSourceInfo json format error.");throw new CommonServiceException(AIModelError.PARAM_ERROR, "dataSourceInfo json format error.");}if (StringUtils.isNotEmpty(dataSourceConfig) && !MyStringUtil.checkJson(dataSourceConfig)) {LOGGER.error("dataSourceConfig json format error.");throw new CommonServiceException(AIModelError.PARAM_ERROR, "dataSourceConfig json format error.");}}/*** Handle data.** @param taskId the task id* @param localFileDir the local file dir*/public abstract void handleData(String taskId, String localFileDir);}

S3DataSetHandle

/*** S3或者minio类型的数据集处理类* @since 2023 -09-15 15:35*/
public class S3DataSetHandle extends DataSetHandle {private static final Logger LOGGER = LoggerFactory.getLogger(S3DataSetHandle.class);/*** Instantiates a new S 3 data set handle.** @param dataSourceInfo the data source info* @param dataSourceConfig the data source config*/public S3DataSetHandle(String dataSourceInfo, String dataSourceConfig) {super(dataSourceInfo, dataSourceConfig);}/*** Check data source.*/@Overridepublic void checkDataSource() {// 1 父类进行参数json格式的校验super.checkDataSource();// 2 具体子类,进行特性校验List<S3DataSourceInfo> s3DataSourceList = JSON.parseArray(dataSourceInfo, S3DataSourceInfo.class);for (S3DataSourceInfo s3DataSource : s3DataSourceList) {// 目前S3,仅支持zip文件if (!Constants.FileType.ZIP.equalsIgnoreCase(s3DataSource.getFileType())) {LOGGER.error("The file type is not supported. fileType:{}", s3DataSource.getFileType());throw new CommonServiceException(AIModelError.PARAM_ERROR,"The file type is not supported. fileType: " + s3DataSource.getFileType());}if (StringUtils.isEmpty(s3DataSource.getFileId()) || StringUtils.isEmpty(s3DataSource.getStoreDirName())) {LOGGER.error("fileId and storeDirName cannot be empty.");throw new CommonServiceException(AIModelError.PARAM_ERROR, "fileId and storeDirName cannot be empty.");}}}/*** Handle data.** @param taskId the task id* @param localFileDir the local file dir*/@Overridepublic void handleData(String taskId, String localFileDir) {// 1 获取配置S3DataSourceConfig s3DataSourceConfig = JSON.parseObject(dataSourceConfig, S3DataSourceConfig.class);// 2 初始化S3客户端S3ClientUtils s3ClientUtils = S3ClientUtils.getInstance(s3DataSourceConfig);for (S3DataSourceInfo s3DataSourceInfo : JSON.parseArray(dataSourceInfo, S3DataSourceInfo.class)) {InputStream s3InputStream = null;try {// 3 获取数据流s3InputStream = s3ClientUtils.download(s3DataSourceConfig.getBucketName(),s3DataSourceInfo.getFileId());// 4 将文件保存在本地磁盘saveFileToLocal(s3InputStream, s3DataSourceInfo, taskId, localFileDir + taskId);} finally {MyIOUtils.closeInputStream(s3InputStream);}}}
}

4.2 网络还原时,不同的采集数据,解析处理方式不同

说明:

  • 创建对象由spring类管理,创建出来的对象是单例的,这个案例1有所不同,案例1,每个类初始化的参数不同。这个案例对象初始化方式一样,只是处理逻辑不同。
  • 在vimpim对象是,因为参数不同所有每次都需要new

工厂类:

/*** The type Ods process factory.** @since 2024 -06-11 10:54*/
@Slf4j
@Service
public class OdsProcessFactory {private static final List<VimPimModelDto> VIM_PIM_MODEL_V2_LIST = new ArrayList<>();private static final String VIM_PIM_MODEL_V2_FILE_PATH = "2.json";private static final List<String> VIM_PIM_MODEL_V2_WHITE_LIST = Arrays.asList();private static final List<VimPimModelDto> VIM_PIM_MODEL_V3_LIST = new ArrayList<>();private static final String VIM_PIM_MODEL_V3_FILE_PATH = "3.json";private static final List<String> VIM_PIM_MODEL_V3_WHITE_LIST = Arrays.asList();/*** The Data source.*/@Resource(name = "gauss")DataSource dataSource;@Autowiredprivate VimPimRepository vimPimRepository;@Autowiredprivate VnfMaeCnDataProcessDomainService vnfMaeCnDataProcessDomainService;@Autowiredprivate VnflocLcmDataProcessDomainService vnflocLcmDataProcessDomainService;static {// 初始化模型数据initModel(VIM_PIM_MODEL_V2_FILE_PATH, VIM_PIM_MODEL_V2_WHITE_LIST, VIM_PIM_MODEL_V2_LIST);initModel(VIM_PIM_MODEL_V3_FILE_PATH, VIM_PIM_MODEL_V3_WHITE_LIST, VIM_PIM_MODEL_V3_LIST);}private static void initModel(String vimPimModelFilePath, List<String> vimPimModelWhiteList,List<VimPimModelDto> vimPimModelList) {}/*** Gets ods process service.** @param taskDto the task dto* @param dataFormat the data format* @return the ods process service*/public DataProcessDomainService getOdsProcessService(CollectionTaskDto taskDto, int dataFormat) {if (OdsParseConstants.OdsDataFormat.VNF_MAECN == dataFormat|| OdsParseConstants.OdsDataFormat.NIC_DSP == dataFormat) {return vnfMaeCnDataProcessDomainService;} else if (OdsParseConstants.OdsDataFormat.VIM_OV2 == dataFormat|| OdsParseConstants.OdsDataFormat.PIM_OV2 == dataFormat) {return getVimPimDataProcessV2DomainService();} else if (OdsParseConstants.OdsDataFormat.VIM_OV3 == dataFormat|| OdsParseConstants.OdsDataFormat.PIM_OV3 == dataFormat) {return getVimPimDataProcessV3DomainService();} else if (OdsParseConstants.OdsDataFormat.VNFLOC_LCM == dataFormat) {return vnflocLcmDataProcessDomainService;} else {// 采集来的数据格式不支持log.warn("Incorrect data dataFormat. taskId:{}, tasksSn:{}, dataFormat:{} ", taskDto.getTaskId(),taskDto.getTaskSn(), dataFormat);}return null;}public VimPimDataProcessV2DomainService getVimPimDataProcessV2DomainService() {return new VimPimDataProcessV2DomainService(VIM_PIM_MODEL_V2_LIST, dataSource, vimPimRepository);}public VimPimDataProcessV3DomainService getVimPimDataProcessV3DomainService() {return new VimPimDataProcessV3DomainService(VIM_PIM_MODEL_V3_LIST, dataSource, vimPimRepository);}
}

在这里插入图片描述

相关文章:

01 设计模式-创造型模式-工厂模式

工厂模式&#xff08;Factory Pattern&#xff09;是 Java 中最常用的设计模式之一&#xff0c;它提供了一种创建对象的方式&#xff0c;使得创建对象的过程与使用对象的过程分离。 工厂模式提供了一种创建对象的方式&#xff0c;而无需指定要创建的具体类。 通过使用工厂模式…...

ComnandLineRunner接口, ApplcationRunner接口

ComnandLineRunner接口, ApplcationRunner接口 介绍&#xff1a; 这两个接口都有一个run方法&#xff0c;执行时间在容器对象创建好后&#xff0c;自动执行run ( )方法。 创建容器的同时会创建容器中的对象&#xff0c;同时会把容器中的对象的属性赋上值&#xff1a; 举例&…...

Swift用于将String拆分为数组的components与split的区别

根据特定分隔符拆分字符串 在 Swift 中&#xff0c;components(separatedBy:) 和 split(separator:) 都可以用于将字符串拆分为数组&#xff0c;但它们有一些关键区别。下面将从返回值类型、性能和功能等角度进行对比。 1. 返回值类型 components(separatedBy:)&#xff1a;…...

docker之redis安装(项目部署准备)

创建网络 docker network create net-ry --subnet172.68.0.0/16 --gateway172.68.0.1 redis安装 #创建目录 mkdir -p /data/redis/{conf,data} #上传redis.conf文件到/data/redis/conf文件夹中 #对redis.conf文件修改 # bind 0.0.0.0 充许任何主机访问 # daemonize no #密码 # …...

使用Maven前的简单准备

目录 一、Maven的准备 1、安装jdk1.8或以上版本 2、下载Maven 3、安装Maven 二、Maven目录的分析 三、Maven的环境变量配置 1、设置MAVEN_HOME环境变量 2、设置Path环境变量 3、验证配置是否完成 一、Maven的准备 1、安装jdk1.8或以上版本 jdk的安装 2、下载Maven…...

Java | Leetcode Java题解之第494题目标和

题目&#xff1a; 题解&#xff1a; class Solution {public int findTargetSumWays(int[] nums, int target) {int sum 0;for (int num : nums) {sum num;}int diff sum - target;if (diff < 0 || diff % 2 ! 0) {return 0;}int neg diff / 2;int[] dp new int[neg …...

阅读笔记 Contemporary strategy analysis Chapter 13

来源&#xff1a;Robert M. Grant - Contemporary strategy analysis (2018) Chapter 13 Implementing Corporate Strategy: Managing the Multibusiness Firm Ⅰ Introduction and Objectives 多业务公司 multibusiness firm由多个独立的业务部门组成&#xff0c;如业务单元…...

Python GUI 编程:tkinter 初学者入门指南——复选框

在本文中&#xff0c;将介绍 tkinter Checkbox 复选框小部件以及如何有效地使用它。 复选框是一个允许选中和取消选中的小部件。复选框可以保存一个值&#xff0c;通常&#xff0c;当希望让用户在两个值之间进行选择时&#xff0c;可以使用复选框。 要创建复选框&#xff0c;…...

使用vscode导入库失败解决方法

导入库失败原因 在使用vscode写python代码时&#xff0c;有时会遇见导入库失败的情况&#xff0c;如下图&#xff1a;无法解析导入“xxxxx” 或者 运行时报错&#xff1a;ModuleNotFoundError: No module named xxxxx。 原因可能有&#xff1a; 根本没有下载库&#xff1b…...

无线网卡知识的学习-- mac80211主要代码流程

一 简介概要: mac80211驱动程序作为Linux内核中管理和控制无线网络接口的核心模块,其主要流程涵盖了从数据帧接收到发送的完整过程。 主要覆盖了7个方面: 1. 数据帧接收流程,2. 数据帧发送流程 3. 频道管理和切换 4. 接口管理 5. 安全和认证 6. 管理和调试 7. 注册和初…...

关于k8s集群高可用性的探究

1. k8s的高可用的核心是什么&#xff1f; 说到核心、本质 意味着要从物理层来考虑技术 k8s是一个容器编排管理工具&#xff0c;k8s受欢迎的时机 是docker容器受欢迎时&#xff0c;因为太多的docker容器&#xff0c;管理起来是一个大工程 那么刚好k8s是google自己用了十来年…...

保姆级Pinpoint(APM)实战教程

什么是Pinpoint Pinpoint是由韩国NAVER公司开发并开源的一款应用程序管理工具&#xff0c;主要针对大规模分布式系统进行性能监控和故障诊断。通过跟踪分布式应用程序之间的事务&#xff0c;帮助分析系统的整体结构以及其中的组件是如何相互连接的。 与其对标的还有Twitter的Zi…...

使用SpringBoot自定义注解+AOP+redisson锁来实现防接口幂等性重复提交

1 前提&#xff0c;整合好springboot和redis,redisson的环境 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId> </dependency> 2 编写自定义注解&#xff0c;注解的作用是标记…...

k8s和ipvs、lvs、ipvsadm,iptables,底层梳理,具体是如何实现的

计算节点的功能&#xff1a; 提供容器运行的环境 kube-proxy的主要功能&#xff1a; 术业有专攻&#xff0c; kube-proxy的主要功能可以概括为4个字 网络规则 那么kube-proxy自己其实是个daemonset控制器跑的 每个节点上都有个的pod 它负责网络规则 其实呢 它还是个小…...

三、归一化与标准化

归一化与标准化 前言一、最小最大值归一化1.1 原理&#xff08;公式&#xff09;1.2 API 介绍1.2.1 参数介绍1.2.2 属性介绍1.2.3 注意事项1.2.4 代码演示 1.3 举例说明 二、标准化2.1 原理&#xff08;公式&#xff09;2.2 API 介绍2.2.1 参数介绍2.2.2 属性介绍2.2.3 注意事项…...

B2105 矩阵乘法

B2105 矩阵乘法 #include <iostream> using namespace std; int main(){int n,m,k;cin>>n>>m>>k;int arr1[n][m];int arr2[m][k];for(auto & line:arr1){for(auto & x: line){cin>>x;}}for(auto & line:arr2){for(auto & x: lin…...

centos之下的mysql8的安装

文章目录 1.mysql.com进入(网址栏)2.xshell操作2.1拖拽上传2.2安装发布包2.3检查情况2.4安装mysql2.5手动启动2.6查看状态2.7查看随机密码2.8登录2.9重置密码 1.mysql.com进入(网址栏) 找下面的这个download按钮&#xff1a; 一直往下面划&#xff1a;找到下面的这个 下面的这个…...

计算机导论

概述 计算机简史 1935年代&#xff0c;英国数学家图灵(Alan Turing)提出“图灵机”&#xff0c;奠定了计算机的理论基础。 1952年&#xff0c;冯诺依曼确定了计算机由运算器、控制器、存储器、输入、输出等5部分组成&#xff08;Von Neumann 体系结构&#xff09;。 60年代…...

力扣209-长度最小的子数组-滑动窗口思想

题目 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回 0 。 示例 1&#xff1a; 输入&am…...

Xilinx 7系列FPGA PCI Express IP核简介

前言&#xff1a;Xilinx7系列FPGA集成了新一代PCI Express集成块&#xff0c;支持8.0Gb/s数据速率的PCI Express 3.0。本文介绍了7系列FPGA PCIe Gen3的应用接口及一些特性。 1. PCI Express规范演进 PCIe是一种高速串行计算机扩展总线标准&#xff0c;旨在替代传统的PCI和AG…...

FreeRTOS临界区避坑指南:taskENTER_CRITICAL()用不对,你的系统可能随时崩溃

FreeRTOS临界区避坑指南&#xff1a;taskENTER_CRITICAL()用不对&#xff0c;你的系统可能随时崩溃 调试嵌入式系统时最令人抓狂的瞬间&#xff0c;往往是那些看似毫无规律的随机崩溃——比如某个传感器数据偶尔错位、系统突然卡死、或是中断服务程序莫名丢失事件。上周我就遇到…...

BetterGI原神自动化工具终极指南:5大核心功能全面解析

BetterGI原神自动化工具终极指南&#xff1a;5大核心功能全面解析 【免费下载链接】better-genshin-impact &#x1f4e6;BetterGI 更好的原神 - 自动拾取 | 自动剧情 | 全自动钓鱼(AI) | 全自动七圣召唤 | 自动伐木 | 自动刷本 | 自动采集/挖矿/锄地 | 一条龙 | 全连音游 | 自…...

从Pad Limit到Core Limit:一次流片失败复盘,聊聊芯片面积估算里的那些‘坑’

从Pad Limit到Core Limit&#xff1a;一次流片失败复盘与芯片面积估算实战指南 那是个周五的深夜&#xff0c;当我收到Foundry发来的最终面积报告时&#xff0c;咖啡杯直接从手中滑落——芯片面积比预算超标23%。这意味着要么接受每片晶圆成本增加40%的残酷现实&#xff0c;要…...

别再手动写CRUD了!用renren-generator 3分钟搞定SpringBoot项目基础代码(附MyBatis-Plus配置)

3分钟极速生成SpringBoot全栈代码&#xff1a;renren-generator深度实践指南 每次启动新项目时&#xff0c;那些重复的CRUD代码是否让你感到厌倦&#xff1f;我曾在一个电商平台项目中&#xff0c;手动编写了37张表的增删改查接口&#xff0c;整整耗费两周时间。直到发现renren…...

告别繁琐SQL!Spring Boot 3.2 + MybatisPlus 3.5.x 配置与常用注解避坑指南

Spring Boot 3.2 MyBatis-Plus 3.5.x 实战避坑手册&#xff1a;从配置陷阱到注解玄学 当你在深夜调试MyBatis-Plus时&#xff0c;是否经历过这样的绝望瞬间——明明按照教程一步步操作&#xff0c;启动时却报出Invalid bound statement&#xff1f;或是发现TableField注解像被…...

别再犯错:Agent项目中的10个常见陷阱及解决方案

别再犯错:Agent项目中的10个常见陷阱及解决方案 关键词:大模型Agent开发、LLM应用落地、RAG优化、Agent工具调用、多Agent协同、生产级Agent、Agent可靠性 摘要:2023年以来大模型Agent成为AI落地的最热方向,无数团队投入到Agent开发中,但90%的Agent Demo最终都卡在上线环节…...

绝地求生罗技鼠标宏:告别手抖,精准压枪的终极指南

绝地求生罗技鼠标宏&#xff1a;告别手抖&#xff0c;精准压枪的终极指南 【免费下载链接】logitech-pubg PUBG no recoil script for Logitech gaming mouse / 绝地求生 罗技 鼠标宏 项目地址: https://gitcode.com/gh_mirrors/lo/logitech-pubg 还在为PUBG中难以控制的…...

UI-TARS-desktop完整指南:Qwen3-4B-Instruct + vLLM + GUI Agent的生产级部署方案

UI-TARS-desktop完整指南&#xff1a;Qwen3-4B-Instruct vLLM GUI Agent的生产级部署方案 想不想拥有一个能帮你操作电脑、浏览网页、处理文件的智能助手&#xff1f;今天要介绍的UI-TARS-desktop&#xff0c;就是这样一个开箱即用的AI智能体。它内置了强大的Qwen3-4B-Instr…...

PP-DocLayoutV3模型部署避坑指南:解决常见环境配置与依赖冲突

PP-DocLayoutV3模型部署避坑指南&#xff1a;解决常见环境配置与依赖冲突 部署一个AI模型&#xff0c;尤其是像PP-DocLayoutV3这样功能强大的文档版面分析模型&#xff0c;本该是件令人兴奋的事。但很多时候&#xff0c;这份兴奋感在第一步——环境配置上&#xff0c;就可能被…...

腾兴热点 | 马斯克打造超级计算机集群 小鹏从车企到AI集团 游宝阁用户突破5千万 Sora负责人离职

2026 全球 AI 与科技产业深度观察&#xff1a;算力军备竞赛、企业战略重构与行业格局重塑2026 年&#xff0c;全球科技产业正迎来新一轮变革浪潮&#xff0c;AI 算力竞赛持续白热化&#xff0c;传统车企加速向科技生态转型&#xff0c;AI 赛道战略收缩与技术落地并行推进&#…...