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

设计杂谈-工厂模式

“工厂”模式在各种框架中非常常见,包括 MyBatis,它是一种创建对象的设计模式。使用工厂模式有很多好处,尤其是在复杂的框架中,它可以带来更好的灵活性、可维护性和可配置性

让我们以 MyBatis 为例,来理解工厂模式及其优点:

MyBatis 中的工厂:SqlSessionFactoryBuilderSqlSessionFactory

在 MyBatis 中,主要的工厂类是 SqlSessionFactoryBuilderSqlSessionFactory

  1. SqlSessionFactoryBuilder(构建器):

    • 它的作用是读取 MyBatis 的配置文件(例如 mybatis-config.xml)或通过 Java 代码构建 Configuration 对象Configuration 对象包含了 MyBatis 的所有配置信息,例如数据源、事务管理器、映射器等。
    • SqlSessionFactoryBuilder 的生命周期很短。一旦 SqlSessionFactory 被创建出来,SqlSessionFactoryBuilder 通常就不再需要了。你可以把它想象成一个“临时的工厂的建造者”。
  2. SqlSessionFactory(会话工厂):

    • 它的作用是根据 Configuration 对象创建一个 SqlSession 对象SqlSession 是 MyBatis 中与数据库交互的核心接口,通过它你可以执行 SQL 语句、管理事务等。
    • SqlSessionFactory 的生命周期通常是整个应用的生命周期。它是一个“持久的工厂”,负责生产 SqlSession

使用工厂模式的好处(以 MyBatis 为例):

  1. 封装对象的创建过程:

    • 工厂模式将对象的创建逻辑封装在一个或多个工厂类中。在 MyBatis 的例子中,创建 SqlSession 的复杂过程被封装在 SqlSessionFactory 中。
    • 客户端代码(你的业务代码)不需要知道创建 SqlSession 的具体细节,只需要从 SqlSessionFactory 获取即可。这降低了客户端代码的复杂性。
  2. 解耦对象的创建和使用:

    • 工厂模式将对象的创建和使用分离。你的业务代码依赖的是 SqlSession 接口,而 SqlSession 的具体实现是由 SqlSessionFactory 负责创建的。
    • 这种解耦使得在需要更换 SqlSession 的实现或者修改其创建方式时,你的业务代码不需要做大的改动,只需要修改工厂的配置即可。
  3. 提高灵活性和可配置性:

    • 通过配置文件(mybatis-config.xml)或编程方式配置 SqlSessionFactoryBuilder,你可以灵活地指定 MyBatis 的各种行为,例如使用哪个数据源、事务管理器、是否开启缓存等等。
    • SqlSessionFactory 会根据这些配置创建出具有相应特性的 SqlSession。这使得框架具有很高的可配置性。
  4. 隐藏对象的创建细节:

    • 工厂可以隐藏对象创建的复杂性,例如对象的初始化参数、依赖关系等。客户端只需要简单地向工厂请求对象,而不需要关心这些内部细节。
    • 在 MyBatis 中,SqlSessionFactory 负责处理数据源的创建、连接池的管理等复杂细节,客户端只需要获取 SqlSession 来执行 SQL。
  5. 控制对象的生命周期:

    • 工厂可以控制所创建对象的生命周期。例如,SqlSessionFactory 可以管理数据源和连接池的生命周期,而 SqlSession 的生命周期通常是请求级别的。
  6. 易于扩展和维护:

    • 当需要引入新的实现或者修改对象的创建逻辑时,只需要修改工厂类或其配置,而不需要修改所有使用该对象的客户端代码。这提高了框架的可扩展性和可维护性。

为了更直观地理解工厂模式的优势,我将提供一个简单的场景,分别用不用工厂模式来实现,并对比它们的差异。

场景:创建不同类型的日志记录器

假设我们需要根据配置创建不同类型的日志记录器,目前有两种:控制台日志记录器 (ConsoleLogger) 和文件日志记录器 (FileLogger)。

1. 不使用工厂模式的实现

interface Logger {void log(String message);
}class ConsoleLogger implements Logger {@Overridepublic void log(String message) {System.out.println("[Console] " + message);}
}class FileLogger implements Logger {private String filePath;public FileLogger(String filePath) {this.filePath = filePath;// 初始化文件写入器等...System.out.println("FileLogger initialized with path: " + filePath);}@Overridepublic void log(String message) {// 将消息写入文件System.out.println("[File] " + message + " (written to " + filePath + ")");}
}public class LoggingServiceWithoutFactory {private String loggerType;private String fileLogPath;public LoggingServiceWithoutFactory(String loggerType, String fileLogPath) {this.loggerType = loggerType;this.fileLogPath = fileLogPath;}public Logger getLogger() {if ("console".equalsIgnoreCase(loggerType)) {return new ConsoleLogger();} else if ("file".equalsIgnoreCase(loggerType)) {return new FileLogger(fileLogPath);} else {throw new IllegalArgumentException("Unsupported logger type: " + loggerType);}}public void logMessage(String message) {Logger logger = getLogger();logger.log(message);}public static void main(String[] args) {LoggingServiceWithoutFactory consoleService = new LoggingServiceWithoutFactory("console", null);consoleService.logMessage("Log to console.");LoggingServiceWithoutFactory fileService = new LoggingServiceWithoutFactory("file", "app.log");fileService.logMessage("Log to file.");// 如果要添加新的日志记录器类型,需要修改 LoggingServiceWithoutFactory}
}

缺点(不使用工厂模式):

  • 紧耦合: LoggingServiceWithoutFactory 类直接依赖于 ConsoleLoggerFileLogger 的具体实现。如果添加新的日志记录器类型,你需要修改 getLogger() 方法。
  • 违反开闭原则: 对修改开放(需要修改 getLogger()),对扩展关闭(不容易在不修改现有代码的情况下添加新的日志记录器)。
  • 创建逻辑分散: 创建不同类型 Logger 的逻辑集中在一个 getLogger() 方法中,如果创建逻辑变得复杂,这个方法会变得难以维护。
  • 客户端需要知道具体的类名: LoggingServiceWithoutFactory 的构造函数需要知道 loggerType 字符串,这间接暴露了具体的实现类名。

2. 使用工厂模式的实现

interface Logger {void log(String message);
}class ConsoleLogger implements Logger {@Overridepublic void log(String message) {System.out.println("[Console] " + message);}
}class FileLogger implements Logger {private String filePath;public FileLogger(String filePath) {this.filePath = filePath;System.out.println("FileLogger initialized with path: " + filePath);}@Overridepublic void log(String message) {System.out.println("[File] " + message + " (written to " + filePath + ")");}
}// 日志记录器工厂接口
interface LoggerFactory {Logger createLogger();
}// 控制台日志记录器工厂
class ConsoleLoggerFactory implements LoggerFactory {@Overridepublic Logger createLogger() {return new ConsoleLogger();}
}// 文件日志记录器工厂
class FileLoggerFactory implements LoggerFactory {private String filePath;public FileLoggerFactory(String filePath) {this.filePath = filePath;}@Overridepublic Logger createLogger() {return new FileLogger(filePath);}
}public class LoggingServiceWithFactory {private LoggerFactory loggerFactory;public LoggingServiceWithFactory(LoggerFactory loggerFactory) {this.loggerFactory = loggerFactory;}public void logMessage(String message) {Logger logger = loggerFactory.createLogger();logger.log(message);}public static void main(String[] args) {LoggerFactory consoleFactory = new ConsoleLoggerFactory();LoggingServiceWithFactory consoleService = new LoggingServiceWithFactory(consoleFactory);consoleService.logMessage("Log to console.");LoggerFactory fileFactory = new FileLoggerFactory("app.log");LoggingServiceWithFactory fileService = new LoggingServiceWithFactory(fileFactory);fileService.logMessage("Log to file.");// 要添加新的日志记录器类型,只需要创建新的 Logger 和 LoggerFactory}
}

优点(使用工厂模式):

  • 解耦: LoggingServiceWithFactory 类依赖于 LoggerFactory 接口,而不是具体的 Logger 实现。具体的 Logger 对象的创建由相应的工厂负责。
  • 符合开闭原则: 要添加新的日志记录器类型,你只需要创建新的 Logger 类和对应的 LoggerFactory 类,而不需要修改 LoggingServiceWithFactory 的代码。
  • 职责分离: 对象创建的逻辑被委托给专门的工厂类,使得 LoggingServiceWithFactory 专注于日志记录的服务逻辑。
  • 隐藏实现细节: LoggingServiceWithFactory 的构造函数接收 LoggerFactory 接口,不需要知道具体的 Logger 实现类名。
  • 更灵活的对象创建: 工厂可以包含更复杂的对象创建逻辑,例如读取配置文件、依赖注入等。

对比总结:

特性不使用工厂模式使用工厂模式
耦合度高,直接依赖具体实现低,依赖抽象(接口)
开闭原则违反,添加新类型需要修改现有代码符合,添加新类型只需创建新类
创建逻辑集中在 getLogger() 方法中分散在不同的工厂类中
灵活性较低,不易于扩展和修改较高,易于扩展和修改
客户端依赖间接依赖具体实现类名依赖抽象工厂接口
维护性随着类型的增加,getLogger() 方法变得难以维护每个工厂类职责单一,更易于维护

咱们用最简单的大白话总结一下“工厂模式”是干啥的,以及为啥像 MyBatis 这样的框架爱用它:

想象一下你要买不同口味的冰淇淋:

不用工厂模式就像这样:

  • 你直接跑到冰柜前,自己翻箱倒柜地找你想要的口味(比如草莓味、巧克力味)。
  • 如果下次出了个新口味(比如抹茶味),你就得知道这个新口味的名字,然后自己去冰柜里找。
  • 如果冰淇淋的制作过程很复杂(比如要加很多配料、特殊冷冻),你买的时候也得稍微了解一下,不然可能买错。

用工厂模式就像这样:

  • 你不去冰柜里直接找,而是找到一个“冰淇淋工厂的售货员”(这就是“工厂”)。
  • 你只需要告诉售货员你想要什么口味(比如“草莓味”)。
  • 售货员知道去哪里、怎么给你拿出正确的冰淇淋。
  • 如果出了新口味,你只需要告诉售货员这个新口味的名字,售货员自然会去工厂里帮你拿。
  • 你不需要知道冰淇淋是怎么做的,售货员(工厂)帮你处理好了一切。

总结一下“工厂模式”:

  • 简单来说: 就是专门找一个“家伙”(工厂)来帮你创建你需要的“东西”(对象),而不是你自己去直接创建。
  • 好处就像上面的冰淇淋例子:
    • 更省事: 你不用自己操心“东西”是怎么被创建出来的,交给工厂就行。
    • 更灵活: 如果想换一种“东西”或者创建“东西”的方式变了,你只需要告诉工厂,不用改你自己的用法。
    • 更好管理: 创建“东西”的逻辑都放在工厂里,管理起来更方便,不会乱糟糟地散在各处。

为啥像 MyBatis 这样的框架爱用工厂模式?

MyBatis 需要创建很多跟数据库打交道的“东西”(比如 SqlSession,就是用来执行 SQL 的)。创建这些“东西”可能挺复杂的,需要配置很多信息(连接哪个数据库、用什么方式等等)。

用了“工厂模式”(SqlSessionFactory 就是个工厂),你的代码就不用去管这些复杂的创建过程了,只需要跟工厂说“给我一个能干活的 SqlSession”,工厂就会根据它的配置帮你弄好。

这样一来:

  • 你的代码更干净: 不用一堆创建 SqlSession 的复杂代码。
  • MyBatis 更灵活: 如果你想换个数据库或者改一下连接方式,只需要改一下 MyBatis 的配置(告诉工厂),你的代码基本不用动。

LoggingServiceWithoutFactory 的构造函数需要知道 loggerType 字符串,这间接暴露了具体的实现类名。 为什么呢

LoggingServiceWithoutFactory 的构造函数中:

public LoggingServiceWithoutFactory(String loggerType, String fileLogPath) {this.loggerType = loggerType;this.fileLogPath = fileLogPath;
}

以及在 getLogger() 方法中:

public Logger getLogger() {if ("console".equalsIgnoreCase(loggerType)) {return new ConsoleLogger();} else if ("file".equalsIgnoreCase(loggerType)) {return new FileLogger(fileLogPath);} else {throw new IllegalArgumentException("Unsupported logger type: " + loggerType);}
}

为什么说构造函数需要知道 loggerType 字符串间接暴露了具体的实现类名?

  1. 字符串 loggerType 的含义: 传递给构造函数的 loggerType 字符串(例如 "console""file")并不是一个抽象的概念,而是直接对应着你希望创建的具体日志记录器类的名称(或其简写)。

  2. getLogger() 方法的逻辑: getLogger() 方法内部的 ifelse if 语句会根据 loggerType 字符串的值来硬编码地创建具体的 Logger 实现类的实例 (new ConsoleLogger()new FileLogger(fileLogPath))。

  3. 客户端代码的依赖: 当客户端代码创建 LoggingServiceWithoutFactory 的实例时,它必须知道要使用哪个 loggerType 字符串,而这个字符串的选择直接决定了最终会创建哪个具体的 Logger 实现类的对象。

    例如,在 main 方法中:

LoggingServiceWithoutFactory consoleService = new LoggingServiceWithoutFactory("console", null); // 客户端需要知道 "console" 对应 ConsoleLogger
LoggingServiceWithoutFactory fileService = new LoggingServiceWithoutFactory("file", "app.log");   // 客户端需要知道 "file" 对应 FileLogger
  • 这里,客户端代码需要使用字符串 "console" 来请求一个控制台日志记录器,使用字符串 "file" 来请求一个文件日志记录器。这些字符串与具体的类名 ConsoleLoggerFileLogger 之间存在着直接的、虽然是通过字符串间接的关联。

  • 修改的影响: 如果你想要添加一个新的日志记录器类型(比如 DatabaseLogger),你需要修改 LoggingServiceWithoutFactorygetLogger() 方法,增加一个新的 else if 分支来创建 DatabaseLogger 的实例。同时,客户端代码也需要知道使用一个新的字符串(比如 "database")来请求这个新的日志记录器。

对比使用工厂模式的情况:

在使用工厂模式的例子中,LoggingServiceWithFactory 的构造函数接收的是 LoggerFactory 接口:

public LoggingServiceWithFactory(LoggerFactory loggerFactory) {this.loggerFactory = loggerFactory;
}

客户端代码直接传递一个实现了 LoggerFactory 接口的具体工厂对象(例如 ConsoleLoggerFactoryFileLoggerFactory):

LoggerFactory consoleFactory = new ConsoleLoggerFactory();
LoggingServiceWithFactory consoleService = new LoggingServiceWithFactory(consoleFactory);LoggerFactory fileFactory = new FileLoggerFactory("app.log");
LoggingServiceWithFactory fileService = new LoggingServiceWithFactory(fileFactory);

在这里,LoggingServiceWithFactory 不直接依赖于具体的 Logger 实现类名,而是依赖于一个抽象的工厂接口。客户端代码虽然仍然需要知道具体的工厂类名,但 LoggingServiceWithFactory 本身与具体的 Logger 实现类解耦了。

总结:

在不使用工厂模式的例子中,loggerType 字符串充当了一个“配置标识符”,客户端代码通过这个标识符间接地告诉 LoggingServiceWithoutFactory 需要创建哪个具体的 Logger 实现类的对象。虽然没有直接使用类名,但字符串的值与具体的类名之间存在着明确的映射关系,这仍然是一种形式的依赖,使得添加新的日志记录器类型需要修改 LoggingServiceWithoutFactory 类的代码。这就是为什么说构造函数需要知道 loggerType 字符串间接暴露了具体的实现类名。

相关文章:

设计杂谈-工厂模式

“工厂”模式在各种框架中非常常见,包括 MyBatis,它是一种创建对象的设计模式。使用工厂模式有很多好处,尤其是在复杂的框架中,它可以带来更好的灵活性、可维护性和可配置性。 让我们以 MyBatis 为例,来理解工厂模式及…...

职坐标IT培训:互联网行业核心技能精讲

在互联网行业高速迭代的今天,掌握全链路核心技能已成为职业发展的关键突破口。职坐标IT培训聚焦行业需求,系统拆解从需求分析到系统部署的完整能力模型,助力从业者构建多维竞争力。无论是产品岗的用户调研与原型设计,还是技术岗的…...

IBM BAW(原BPM升级版)使用教程第十二讲

续前篇! 一、用户界面:Process Portal和Workplace Process Portal 和 Workplace 都是 IBM Business Automation Workflow (BAW) 中提供的 Web 界面,供用户查看和处理流程任务、监控流程状态等,但它们之间有着不同的历史背景和功…...

2025 年福建省职业院校技能大赛网络建设与运维赛项Linux赛题解析

​ 准备环境:系统安装及网络配置 [!TIP] 接下来将完全按照国赛评分标准进行,过程中需要掌握基础的Linux命令以及理解Linux系统,建议大家在做题前将Linux基础命令熟练运用 网络建设与运维赛项详细教程请联系主页一、X86架构计算机操作系统安装…...

Netty在Java网络编程中的应用:实现高性能的异步通信

Netty在Java网络编程中的应用:实现高性能的异步通信 在当今的分布式系统中,高效、稳定的网络通信是保障系统运行的关键。Java作为一门广泛使用的编程语言,提供了多种网络编程方式,但传统的Socket编程在面对高并发场景时往往显得力…...

[高阶数据结构]二叉树经典面试题

二叉树经典面试题:: 目录 二叉树经典面试题:: 1.根据二叉树创建字符串 2.二叉树的层序遍历 3.二叉树的层序遍历II 4.二叉树的最近公共祖先 5.二叉树与双向链表 6.从前序与中序序列构造二叉树 7.从中序与后序序列构造二叉…...

第一章 应急响应-webshell查杀

远程连接一下 我们先查找一下网站的目录,到网站页面,可以看到有很多php文件,这样我们可以大致确定黑客上传的应该是php木马 通过ls -a 查看一下隐藏文件 现在我们查看一下各个php文件的内容 可以看到shell.php是一句话木马,但没…...

残差网络(ResNet)

残差网络(Residual Network, ResNet)介绍 残差网络(ResNet)是由微软研究院的何恺明(Kai Ming He)等人于2015年提出的深度卷积神经网络架构,其核心思想是通过残差连接(Skip Connectio…...

全视通智慧病房无感巡视解决方案:科技赋能,重塑护理巡视新篇

护理巡视是保障患者安全与护理质量的关键环节。现有特级、一、二、三级护理虽有明确巡视要求,但从护士手工填写记录表,均存在诸多弊端。或因需人工操作易遗忘、无法准确界定巡视人员,或因设备携带不便、需额外充电、布网复杂等,导…...

【数据结构入门训练DAY-32】LETTERS

本文介绍了一个关于使用深度优先搜索(DFS)解决字母矩阵问题的训练内容。题目要求在一个RS的大写字母矩阵中,从左上角开始移动,可以上下左右四个方向移动,但不能重复经过相同的字母,目标是找出最多能经过的不…...

Linux笔记---信号(上)

1. 信号的概念 Linux下的信号机制是一种进程间通信(IPC)的方式,用于在不同进程之间传递信息。 信号是一种异步的信息传递方式,这意味着发送信号的进程只发送由信号作为载体的命令,而并不关心接收信号的进程如何处置这…...

FanControl(电脑风扇转速控制软件) v224 中文版

FanControl是一款用于控制计算机风扇速度的软件。它能够监测计算机的内部温度,并根据温度的变化来自动调整风扇的速度,以保持计算机的散热效果和稳定运行。 软件功能 温度监测:实时监测计算机的内部温度,显示在界面上。 风扇速度控…...

推理加速新范式:火山引擎高性能分布式 KVCache (EIC)核心技术解读

资料来源:火山引擎-开发者社区 分布式 KVCache 的兴起 背景 在大模型领域,随着模型参数规模的扩大和上下文长度增加,算力消耗显著增长。在 LLM 推理过程中,如何减少算力消耗并提升推理吞吐已经成为关键性优化方向。以多轮对话场…...

2025年5月12日第一轮

1.百词斩 2.阅读 3.翻译 4.单词 radical 激进的 Some people in the US have asserted that forgiving student loan debt is one way to stimulate the economy and give assistance to those in need. 1.数学 Hainan was the second island on the Taiwan,a province whi…...

Spark目前支持的部署模式。

一、本地模式(Local Mode) 特点: 在单台机器上运行,无需集群。主要用于开发、测试和调试。所有组件(Driver、Executor)在同一个 JVM 中运行。 启动命令: bash spark-submit --master local[*]…...

如何理解“数组也是对象“——Java中的数组

在Java中,数组确实是一种特殊的对象,这一点经常让初学者感到困惑。本文将深入探讨数组的对象本质,并通过代码示例展示数组作为对象的特性。 数组是对象的证据 1. 数组继承自Object类 所有Java数组都隐式继承自java.lang.Object类&#xff…...

第二章、物理层

目录 2.1、物理层的基本概念 2.2、数据通信的基础知识 2.2.1、数据通信系统的模型 2.2.2、有关信道的几个基本概念 调制的方法 常用的编码方式 基本的带通调制 2.2.3、信道的极限容量 信道能够通过的频率范围 2.3、物理层下面的传输媒介 2.3.1、导引型传输媒体 &…...

UART16550 IP core笔记二

XIN时钟 表示use external clk for baud rate选型&#xff0c;IP核会出现Xin时钟引脚 XIN输入被外部驱动&#xff0c;也就是外部时钟源&#xff0c;那么外部时钟必须要满足特定的要求&#xff0c;就是XIN 的range范围是xin<S_AXI_CLK/2,如果不满足这个条件&#xff0c;那么A…...

websocketpp 安装及使用

介绍 WebSocket 是从 HTML5 开始支持的一种网页端和服务端保持长连接的消息推送机制。 传统的 web 程序都是属于 "一问一答" 的形式&#xff0c;即客户端给服务器发送了一个 HTTP 请求&#xff0c;服务器给客户端返回一个 HTTP 响应。这种情况下服务器是属于被动…...

【大数据】MapReduce 编程--WordCount

API 是“Application Programming Interface”的缩写&#xff0c;即“应用程序编程接口” Hadoop 提供了一套 基于 Java 的 API&#xff0c;用于开发 MapReduce 程序、访问 HDFS、控制作业等 MapReduce 是一种 分布式并行计算模型&#xff0c;主要用于处理 大规模数据集。它将…...

北京市通州区经信局对新增通过国家级生成式人工智能及深度合成算法备案企业给予100w、20w一次性补贴

北京市通州区经济和信息化局 关于发布支持北京城市副中心数字经济高质量发展的实施指南&#xff08;第一批&#xff09;的通知 各有关单位&#xff1a; 为培育千亿级数字经济产业集群&#xff0c;促进数字经济和实体经济深度融合&#xff0c;助推北京城市副中心产业高质量发展&…...

机器学习驱动的智能化电池管理技术与应用

在人工智能与电池管理技术融合的背景下&#xff0c;电池科技的研究和应用正迅速发展&#xff0c;创新解决方案层出不穷。从电池性能的精确评估到复杂电池系统的智能监控&#xff0c;从数据驱动的故障诊断到电池寿命的预测优化&#xff0c;人工智能技术正以其强大的数据处理能力…...

GTC2025——英伟达布局推理领域加速

英伟达GTC2025大会于今年3月18日举行&#xff0c;会上NVIDIA CEO黄仁勋展示了其过去所取得的成就&#xff0c;以及未来的布局目标——通过纵向扩展&#xff08;scale out&#xff09;和横向扩展&#xff08;scale up&#xff09;解决终极的计算问题——推理。本文将回顾NVIDIA在…...

5.12 note

Leetcode 图 邻接矩阵的dfs遍历 class Solution { private: vector<vector<int>> paths; vector<int> path; void dfs(vector<vector<int>>& graph, int node) { // 到n - 1结点了保存 if (node graph.size() - 1)…...

Java Spring Boot项目目录规范示例

以下是一个典型的 Java Spring Boot 项目目录结构规范示例&#xff0c;结合了分层架构和模块化设计的最佳实践&#xff1a; text 复制 下载 src/ ├── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── myapp/ │…...

记录裁员后的半年前端求职经历

普通的人生终起波澜 去年下半年应该算是我毕业以来发生人生变故最多的一段时间。 先是 7 月份的时候发作了一次急性痛风&#xff0c;一个人在厦门&#xff0c;坐在床上路都走不了&#xff0c;那时候真的好想旁边能有个人能扶我去医院&#xff0c;真的是感受到 10 级的孤独。尝…...

学习黑客BitLocker与TPM详解

BitLocker与TPM详解&#xff1a;数据加密的坚固堡垒 &#x1f510;&#x1f6e1;️ 学习目标&#xff1a;掌握BitLocker加密原理、TPM工作机制及其配置方法&#xff0c;提升数据安全防护水平 1. 数据保护的最后防线&#xff1a;BitLocker与TPM简介 &#x1f4bc; 在当今世界&a…...

综合实验二之grub2密文加密

实验二、grub2密文加密 Grub2 密文加密的作用&#xff1a; 保护系统安全&#xff1a; 防止未经授权的用户在系统启动时进入 Grub2 菜单&#xff0c;通过修改启动参数来绕过系统的安全机制&#xff0c;进而访问或篡改系统文件和数据。例如&#xff0c;恶意用户可能试图通过修改启…...

【Java学习】Lambda表达式

目录 一、函数式匿名 1.环境确定 2.Lambda部分实现 二、函数式书写 Lambda表达式&#xff1a; 三、函数式接口 1.Consumer行为接口 1.1Lambda匿名实现(核心) 1.2创建使用全过程 1.2.1创建匿名子类实例 1.2.1.1环境确定 1.2.1.2匿名实现 1.2.2向上转型 1.2.3Lamb…...

精益数据分析(55/126):双边市场模式的挑战、策略与创业阶段关联

精益数据分析&#xff08;55/126&#xff09;&#xff1a;双边市场模式的挑战、策略与创业阶段关联 在创业和数据分析的学习旅程中&#xff0c;我们持续探索不同商业模式的奥秘。今天&#xff0c;依旧怀揣着与大家共同进步的想法&#xff0c;深入研读《精益数据分析》&#xf…...

人工智能100问☞第21问:神经网络如何模拟人脑结构?

目录 一、通俗解释 二、专业解析 三、权威参考 神经网络通过​​分层连接的人工神经元​​模拟人脑结构,其中输入层接收信号(模拟树突接收信息),隐藏层通过权重调整(模拟突触可塑性)进行特征提取,输出层生成结果(类似轴突传递信号),并利用反向传播机制(类比生物神…...

Vue 3 实现转盘抽奖效果

&#x1f3a1; 使用 Vue 3 实现转盘抽奖效果 在移动端或营销活动中&#xff0c;转盘抽奖是一种非常常见的互动方式。本文基于 Vue 3 TypeScript 实现一个视觉炫酷、逻辑完整的转盘抽奖功能&#xff0c;并支持「指定奖品必中」的逻辑。 iShot_2025-05-12_11.31.27 &#x1f9f…...

Python 处理图像并生成 JSONL 元数据文件 - 灵活text版本

Python 处理图像并生成 JSONL 元数据文件 - 灵活text版本 flyfish import os import json import argparse from PIL import Image from xpinyin import Pinyinclass ImageConverter:def __init__(self, src_folder, dest_folder, target_size1024, output_format"JPEG&…...

LeRobot 项目部署运行逻辑(七)—— ACT 在 Mobile ALOHA 训练与部署

全部流程为&#xff1a;硬件配置 -> 环境安装 -> 遥操作数据采集 -> 数据集可视化 -> 策略训练 -> 策略评估 在之前的笔记中已经完成了绝大部分&#xff0c;最后再记录一下最后的训练部署&#xff0c;算是最简单的部分了 目录 1 ACT 训练 2 ALOHA 部署 3 更…...

【NextPilot日志移植】ULog

&#x1f4da; ULog 日志系统详解 关键词&#xff1a;结构化日志、飞行数据记录、自描述格式、嵌入式系统、PX4、NextPilot &#x1f9e0; 一、ULog 是什么&#xff1f; ULog&#xff08;Universal Log&#xff09; 是 PX4/NextPilot 飞控系统中使用的结构化日志格式&#xff…...

扩展:React 项目执行 yarn eject 后的 scripts 目录结构详解

扩展&#xff1a;React 项目执行 yarn eject 后的 scripts 目录结构详解 什么是 yarn eject&#xff1f;scripts 目录结构与说明各脚本说明说明 什么是 yarn eject&#xff1f; yarn eject 是 Create React App&#xff08;简称 CRA&#xff09;提供的一条命令&#xff0c;用于…...

Android11.0 framework第三方无源码APP读写断电后数据丢失问题解决

1.前言 在11.0中rom定制化开发中,在某些产品开发中,在某些情况下在App用FileOutputStream读写完毕后,突然断电 会出现写完的数据丢失的问题,接下来就需要分析下关于使用FileOutputStream读写数据的相关流程,来实现相关 功能 2.framework第三方无源码APP读写断电后数据丢…...

多样本整合Banksy空间聚类分析(Visium HD, Xenium, CosMx)

在空间数据分析中&#xff0c;传统的单细胞聚类算法&#xff0c;例如Seurat和Scanpy中的lovain和leiden等聚类算法&#xff0c;通常在处理空间数据时忽略了空间信息。然而&#xff0c;由于细胞状态受其周围细胞的影响&#xff0c;将转录组数据与细胞的空间信息结合起来进行聚类…...

【2025最新】Vm虚拟机中直接使用Ubuntu 免安装过程直接使用教程与下载

Ubuntu 是一个基于 Debian 的自由开源 Linux 操作系统&#xff0c;面向桌面、服务器和云计算平台广泛应用。 由英国公司 Canonical Ltd. 维护和发布&#xff0c;Ubuntu 强调易用性、安全性和稳定性&#xff0c;适合个人用户、开发者以及企业部署使用。 Ubuntu 默认使用 GNOME …...

【Leetcode】系列之206反转链表

反转链表 题目描述解决思路过程示例代码示例结果展示 总结 题目描述 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 解决思路 next_node:临时存放当前指针指向下一个指针的变量&#xff1b;pre:存放空指针&#xff1b;curr&#xff1…...

图灵爬虫练习平台第十九题js逆向

题十九&#xff1a;法外狂徒 该题适合JS逆向学习的小伙伴练习&#xff0c;模拟国内某大型网站 数据加密设计&#xff0c;给大家练练手 还是先f12看看是什么加密&#xff0c;发现是 返回数据最后加密了 还是先堆栈分析一下&#xff0c;直接点进去 打上断点分析一下&#xff0c;…...

Ubuntu 22初始配置(root、ssh)

1.设置root密码 并启用root用户 sudo passwd root sudo passwd -u root 2.安装ssh apt install openssh-server systemctl enable --now ssh 3.支持root通过ssh登录 vim /etc/ssh/sshd_config 是sshd_config(服务端) 不是ssh_config&#xff08;客户端&#xff09; 最后增加一…...

css3响应式布局

css3响应式布局 响应式设计是现代网页开发的重要组成部分&#xff0c;它确保网页在不同的屏幕尺寸上都有良好的显示效果。 在CSS中&#xff0c;实现响应式布局是一种常用的技术&#xff0c;旨在使网页能够根据用户的设备和屏幕尺寸自动调整其布局和样式。这种技术对于确保网站…...

【DeepSeek问答记录】请结合实例,讲解一下pytorch的DataLoader的使用方法

PyTorch的DataLoader是数据加载的核心工具&#xff0c;可高效处理批量数据、并行加载和自动打乱。以下是一个结合实例的分步讲解&#xff1a; 1. 基础使用流程 import torch from torch.utils.data import Dataset, DataLoader# 自定义数据集类&#xff08;必须实现__len__和…...

Codeforces Round 1024 (Div. 2)(A-D)

题面链接&#xff1a;Dashboard - Codeforces Round 1024 (Div. 2) - Codeforces A. Dinner Time 思路 一共n个数被分成n/p个区间&#xff0c;每个区间内的和是q&#xff0c;如果还有除构成区间外剩余的数那么就一定能构造&#xff0c;如果没有剩余就看所有区间的和是否等于…...

大语言模型强化学习双强:OpenRLHF与verl技术解析

引言 随着大语言模型&#xff08;LLM&#xff09;参数规模突破千亿级&#xff0c;如何高效完成基于人类反馈的强化学习&#xff08;RLHF&#xff09;训练成为行业焦点。OpenRLHF与verl作为开源社区两大标杆框架&#xff0c;分别以Ray分布式架构和HybridFlow混合控制器为核心&a…...

ARM Cortex-M3内核详解

目录 一、ARM Cortex-M3内核基本介绍 &#xff08;一&#xff09;基本介绍 &#xff08;二&#xff09;主要组成部分 &#xff08;三&#xff09;调试系统 二、ARM Cortex-M3内核的内核架构 三、ARM Cortex-M3内核的寄存器 四、ARM Cortex-M3内核的存储结构 五、ARM Co…...

关于高并发GIS数据处理的一点经验分享

1、背景介绍 笔者过去几年在参与某个大型央企的项目开发过程中,遇到了十分棘手的难题。其与我们平常接触的项目性质完全不同。在一般的项目中,客户一般只要求我们能够通过桌面软件对原始数据进行加工处理,将各类地理信息数据加工处理成地图/场景和工作空间,然后再将工作空…...

vue3+flask+sqlite前后端项目实战

基础环境安装 pycharm 下载地址&#xff1a; https://www.jetbrains.com/zh-cn/pycharm/download/?sectionwindows vscode 下载地址 https://code.visualstudio.com/docs/?dvwin64user python 下载地址 https://www.python.org/downloads/windows/ Node.js&#xff08;含npm…...

支付宝API-SKD-GO版

前言 支付宝api的sdk没有提供go版&#xff0c;这里自己封装了一个go版的sdk&#xff0c;有需要的朋友可以自取使用 支付宝 AliPay SDK for Go, 集成简单&#xff0c;功能完善&#xff0c;持续更新&#xff0c;支持公钥证书和普通公钥进行签名和验签。 安装 go get github.c…...