设计模式 行为型 访问者模式(Visitor Pattern)与 常见技术框架应用 解析

访问者模式(Visitor Pattern)是一种行为设计模式,它允许你在不改变元素类的前提下定义作用于这些元素的新操作。这种模式将算法与对象结构分离,使得可以独立地变化那些保存在复杂对象结构中的元素的操作。
假设我们有一个复杂的对象结构,例如一个包含多种图形(圆形、矩形、三角形)的绘图系统。我们可能需要对这些图形进行多种操作,如计算面积、绘制轮廓、计算周长等。如果将这些操作的代码都放在图形类中,会使图形类变得非常臃肿。访问者模式就像是一个外来的“访问者”,它可以独立于图形类定义这些操作,然后在需要的时候“访问”图形并执行相应的操作。
一、核心思想
核心思想是将算法从对象的结构中分离出来,封装在独立的访问者对象中。这样一来,就可以在不修改对象结构的情况下,为该结构中的元素添加新的操作或行为。
二、定义与结构
- 定义:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
- 结构:
- 访问者(Visitor):抽象类或者接口,定义了对每个具体元素访问的操作方法。
- 具体访问者(ConcreteVisitor):实现访问者接口,实现对具体元素的操作。
- 元素(Element):抽象类或者接口,定义了一个接受访问者的方法(
accept方法)。 - 具体元素(ConcreteElement):实现元素接口,在
accept方法中调用访问者对应的操作方法。 - 对象结构(ObjectStructure):包含可以被访问的元素集合,提供方法让访问者访问它的元素。
三、角色
- 访问者(Visitor):
- 这是一个抽象角色,用于声明访问具体元素的方法。例如,在图形系统中,它可能有
visitCircle、visitRectangle等方法,这些方法的参数通常是对应的具体元素。它定义了对不同类型元素进行操作的统一接口。
- 这是一个抽象角色,用于声明访问具体元素的方法。例如,在图形系统中,它可能有
- 具体访问者(ConcreteVisitor):
- 实现了访问者接口。它为每个访问方法提供了具体的实现,这些实现包含了针对具体元素的实际操作逻辑。比如,一个计算图形面积的具体访问者,会在
visitCircle方法中实现计算圆形面积的逻辑,在visitRectangle方法中实现计算矩形面积的逻辑等。
- 实现了访问者接口。它为每个访问方法提供了具体的实现,这些实现包含了针对具体元素的实际操作逻辑。比如,一个计算图形面积的具体访问者,会在
- 元素(Element):
- 抽象元素角色,通常是一个抽象类或接口,定义了
accept方法。这个方法接受一个访问者对象作为参数,用于将当前元素自身传递给访问者,以便访问者执行相应的操作。
- 抽象元素角色,通常是一个抽象类或接口,定义了
- 具体元素(ConcreteElement):
- 实现了抽象元素角色定义的接口或抽象类。在
accept方法中,它会调用访问者的相应方法,并将自身作为参数传递进去。例如,圆形类(Circle)作为具体元素,在其accept方法中会调用访问者的visitCircle方法,并把自己(圆形对象)传递给访问者。
- 实现了抽象元素角色定义的接口或抽象类。在
- 对象结构(ObjectStructure):
- 这个角色用于管理和存储元素对象。它提供了方法来遍历元素集合,让访问者能够访问其中的每个元素。比如,在绘图系统中,对象结构可能是一个包含所有图形的列表,它有一个方法可以遍历这个列表,然后让访问者访问每个图形。
四、实现步骤及代码示例
- 步骤一:定义访问者接口和具体访问者类
// 访问者接口
interface Visitor {void visitCircle(Circle circle);void visitRectangle(Rectangle rectangle);
}
// 具体访问者类(计算面积)
class AreaCalculatorVisitor implements Visitor {@Overridepublic void visitCircle(Circle circle) {double area = Math.PI * circle.getRadius() * circle.getRadius();System.out.println("圆形面积:" + area);}@Overridepublic void visitRectangle(Rectangle rectangle) {double area = rectangle.getWidth() * rectangle.getHeight();System.out.println("矩形面积:" + area);}
}
- 步骤二:定义元素接口和具体元素类
// 元素接口
interface Shape {void accept(Visitor visitor);
}
// 具体元素类(圆形)
class Circle implements Shape {private double radius;public Circle(double radius) {this.radius = radius;}public double getRadius() {return radius;}@Overridepublic void accept(Visitor visitor) {visitor.visitCircle(this);}
}
// 具体元素类(矩形)
class Rectangle implements Shape {private double width;private double height;public Rectangle(double width, double height) {this.width = width;this.height = height;}public double getWidth() {return width;}public double getHeight() {return height;}@Overridepublic void accept(Visitor visitor) {visitor.visitRectangle(this);}
}
- 步骤三:定义对象结构类并使用访问者模式
import java.util.ArrayList;
import java.util.List;
// 对象结构类
class ShapeList {private List<Shape> shapes = new ArrayList<>();public void addShape(Shape shape) {shapes.add(shape);}public void accept(Visitor visitor) {for (Shape shape : shapes) {shape.accept(visitor);}}
}
// 主程序测试
public class Main {public static void main(String[] args) {ShapeList shapeList = new ShapeList();shapeList.addShape(new Circle(3.0));shapeList.addShape(new Rectangle(4.0, 5.0));Visitor areaCalculator = new AreaCalculatorVisitor();shapeList.accept(areaCalculator);}
}
- 在上述代码中,
Visitor是访问者接口,AreaCalculatorVisitor是具体访问者,用于计算图形面积。Shape是元素接口,Circle和Rectangle是具体元素。ShapeList是对象结构,用于管理图形对象。在main方法中,我们创建了图形对象列表,添加了圆形和矩形对象,然后创建了面积计算访问者,并让对象结构接受访问者来计算每个图形的面积。
五、常见技术框架应用
1、编译器中的语法树遍历
- 在编译器开发中,语法树是一个复杂的对象结构。访问者模式可以用于遍历语法树并执行语义分析或代码生成等操作。
- 步骤一:定义语法树节点(元素)接口和具体节点类
// 语法树节点接口
interface ASTNode {void accept(ASTVisitor visitor);
}
// 具体节点类(表达式节点)
class ExpressionNode implements ASTNode {// 表达式内容等属性@Overridepublic void accept(ASTVisitor visitor) {visitor.visitExpressionNode(this);}
}
// 具体节点类(语句节点)
class StatementNode implements ASTNode {// 语句内容等属性@Overridepublic void accept(ASTVisitor visitor) {visitor.visitStatementNode(this);}
}
- 步骤二:定义访问者接口和具体访问者类(语义分析访问者)
// 访问者接口
interface ASTVisitor {void visitExpressionNode(ExpressionNode node);void visitStatementNode(StatementNode node);
}
// 具体访问者类(语义分析)
class SemanticAnalysisVisitor implements ASTVisitor {@Overridepublic void visitExpressionNode(ExpressionNode node) {// 进行表达式语义分析,如检查操作数类型等}@Overridepublic void visitStatementNode(StatementNode node) {// 进行语句语义分析,如检查变量声明等}
}
- 步骤三:定义语法树(对象结构)类并使用访问者模式进行遍历
import java.util.ArrayList;
import java.util.List;
// 语法树类
class SyntaxTree {private List<ASTNode> nodes = new ArrayList<>();public void addNode(ASTNode node) {nodes.add(node);}public void accept(ASTVisitor visitor) {for (ASTNode node : nodes) {node.accept(visitor);}}
}
// 主程序测试(假设在编译器的某个阶段)
public class Compiler {public static void main(String[] args) {SyntaxTree syntaxTree = new SyntaxTree();ASTNode expressionNode = new ExpressionNode();ASTNode statementNode = new StatementNode();syntaxTree.addNode(expressionNode);syntaxTree.addNode(statementNode);ASTVisitor semanticAnalysisVisitor = new SemanticAnalysisVisitor();syntaxTree.accept(semanticAnalysisVisitor);}
}
- 这里的语法树由各种语法节点组成,通过访问者模式,语义分析访问者可以遍历语法树并对每个节点进行语义分析,而不需要将语义分析代码嵌入到语法树节点的内部。
2、前端框架中的访问者模式示例
以下是一些前端框架中访问者模式应用的具体例子:
处理复杂UI组件树
假设我们有一个复杂的用户界面,它由各种不同的UI组件构成,比如按钮、输入框、下拉菜单等。每个组件可能都需要执行特定的操作,例如验证、序列化或渲染。我们可以定义一个Visitor来封装这些操作,而不是将所有逻辑都放在组件内部,这样可以使代码更加模块化和易于维护。
// 抽象访问者 (Abstract Visitor)
class UIComponentVisitor {visitButton(button) { }visitInput(input) { }visitDropdown(dropdown) { }
}// 具体访问者 (Concrete Visitors)
class ValidatorVisitor extends UIComponentVisitor {visitButton(button) {// 验证按钮的逻辑console.log('Validating button:', button);}visitInput(input) {if (!input.value) {console.error('Input is required:', input);} else {console.log('Input validated:', input);}}visitDropdown(dropdown) {// 验证下拉菜单的逻辑console.log('Validating dropdown:', dropdown);}
}class SerializerVisitor extends UIComponentVisitor {visitButton(button) {// 序列化按钮的状态console.log('Serializing button:', button);}visitInput(input) {// 序列化输入框的值console.log('Serializing input value:', input.value);}visitDropdown(dropdown) {// 序列化下拉菜单的选择console.log('Serializing dropdown selection:', dropdown.selectedOptions);}
}// 抽象元素 (Abstract Element)
class UIComponent {constructor() {this.name = 'UIComponent';}accept(visitor) {visitor[`visit${this.constructor.name}`](this);}
}// 具体元素 (Concrete Elements)
class Button extends UIComponent {constructor(text) {super();this.text = text;this.name = 'Button';}
}class Input extends UIComponent {constructor(value) {super();this.value = value;this.name = 'Input';}
}class Dropdown extends UIComponent {constructor(options, selectedOptions) {super();this.options = options;this.selectedOptions = selectedOptions;this.name = 'Dropdown';}
}// 使用访问者模式
const components = [new Button('Submit'), new Input('Some text'), new Dropdown(['Option1', 'Option2'], ['Option1'])];const validator = new ValidatorVisitor();
const serializer = new SerializerVisitor();components.forEach(component => component.accept(validator));
console.log('\n');
components.forEach(component => component.accept(serializer));
在这个例子中,ValidatorVisitor和SerializerVisitor是具体的访问者,它们实现了针对不同类型UI组件的不同行为。UIComponent及其子类作为具体元素,提供了accept方法以接受访问者的访问。这种方式使得我们可以很容易地添加新的操作类型,而无需修改现有的UI组件类。
React 中的虚拟 DOM 遍历与更新(间接体现访问者模式思想)
- 背景:
在 React 中,虚拟 DOM(Virtual DOM)是一个关键概念。它是真实 DOM 结构在 JavaScript 对象层面的一种表示,通过对比虚拟 DOM 的前后状态变化来决定如何高效地更新真实 DOM。 - 分析:
- 元素(类似访问者模式中的元素角色):React 组件对应的虚拟 DOM 节点可以看作是元素。例如,一个简单的
<div>组件在虚拟 DOM 里会被表示成一个包含各种属性(如props、children等)的 JavaScript 对象,它定义了accept(这里没有显式的accept方法名,但有类似机制)操作,也就是允许 React 的更新机制来处理它。 - 访问者(类似访问者模式中的访问者角色):React 的
Diffing算法(用于对比新旧虚拟 DOM 差异的机制)以及后续的Reconciliation过程(协调更新的过程)可以看作是访问者。Diffing算法会遍历虚拟 DOM 树(从根节点开始),访问每个虚拟 DOM 节点(元素),去判断节点的类型、属性以及子节点等是否发生了变化,这个过程就类似访问者对不同元素进行访问并执行相应操作。例如,当检测到一个<div>组件的props发生了改变,访问者(更新机制)就会执行对应的更新真实 DOM 中该<div>对应部分的操作,比如更新style属性或者innerHTML等。 - 具体过程示例:
假如有一个简单的 React 组件结构如下:
- 元素(类似访问者模式中的元素角色):React 组件对应的虚拟 DOM 节点可以看作是元素。例如,一个简单的
function App() {return (<div className="app"><h1>Hello</h1><p>World</p></div>);
}
当组件的状态发生改变(比如 className 变为 app-new),React 会重新构建新的虚拟 DOM 树,然后通过 Diffing 算法这个“访问者”去遍历新旧虚拟 DOM 树的各个节点(元素),对比发现 <div> 节点的 className 属性变化了,就会执行相应的更新真实 DOM 中对应 <div> 元素的操作,将 class 属性更新为 app-new。
Vue.js 的模板编译与指令解析(体现访问者模式思路)
- 背景:
Vue.js 在将模板(template)编译成渲染函数(render函数)以及解析模板中的指令(如v-if、v-for等)时运用了类似访问者模式的思路。 - 分析:
- 元素(类似访问者模式中的元素角色):模板中的 HTML 标签以及文本节点等可以看作是元素。例如
<div v-if="show">{{ message }}</div>中的<div>标签、文本插值{{ message }}等,它们构成了整个模板这个“数据结构”,并且每个元素都能被访问处理。 - 访问者(类似访问者模式中的访问者角色):Vue 的模板编译器就是访问者。它会对模板这个元素集合进行遍历,解析每个元素。比如,对于指令类的元素,像遇到
v-if指令时,访问者(编译器)会解析出条件判断逻辑,根据对应的数据(show变量的值)来决定是否生成该<div>元素的渲染代码;对于文本插值元素{{ message }},访问者会解析出需要将对应的数据(message值)渲染到此处的操作。 - 具体过程示例:
假设我们有如下 Vue 模板:
- 元素(类似访问者模式中的元素角色):模板中的 HTML 标签以及文本节点等可以看作是元素。例如
<template><div><p v-if="isShow">This is visible</p><p v-else>This is hidden</p><span>{{ greeting }}</span></div>
</template>
当 Vue 进行模板编译时,编译器这个“访问者”会遍历整个模板的各个元素。对于带有 v-if 指令的 <p> 元素,它会检查 isShow 数据的值,如果为 true,则生成将 This is visible 渲染到页面的相关代码逻辑;对于文本插值的 <span> 元素,编译器会根据 greeting 变量的值,生成将其正确渲染到对应位置的代码,从而实现模板到渲染函数的转换,后续基于渲染函数就能更新页面 DOM 了。
Ember.js 的渲染系统(部分体现访问者模式)
- 背景:
Ember.js 有一套自己的渲染机制,用于根据定义的模板和组件来生成和更新页面内容。 - 分析:
- 元素(类似访问者模式中的元素角色):在 Ember.js 中,组件对应的模板内容、DOM 元素等可以视为元素。例如,一个自定义的组件模板里包含的各种 HTML 标签、绑定的数据等组成了要处理的元素集合。
- 访问者(类似访问者模式中的访问者角色):Ember.js 的渲染引擎和相关的更新机制充当访问者。渲染引擎会遍历组件的模板元素,比如遇到绑定数据的地方(类似
{{someProperty}}),访问者(渲染引擎)会去获取对应的数据值,并将其正确渲染到 DOM 中;当组件状态变化触发更新时,更新机制同样会访问各个元素,判断哪些元素需要重新渲染,然后执行相应的更新操作。 - 具体过程示例:
假设有一个 Ember.js 组件的模板如下:
{{! my-component.hbs }}
<h2>{{title}}</h2>
<p>Description: {{description}}</p>
当 Ember.js 渲染这个组件时,渲染引擎这个“访问者”会访问模板中的每个元素,对于 {{title}} 和 {{description}} 这些绑定数据的元素,会从组件对应的 JavaScript 对象(包含 title 和 description 等属性)中获取相应的值,然后将其渲染到对应的 HTML 标签内,生成最终的 DOM 结构展示给用户。当组件的 title 或 description 属性值发生变化时,更新机制又会作为访问者再次访问这些元素,重新获取新值并更新 DOM 展示。
总之,在前端框架中,访问者模式(或其类似思路)常被用于高效地处理页面元素的渲染、更新以及对模板、DOM 相关结构的操作,使得代码结构更清晰,便于扩展和维护不同的功能逻辑。
六、应用场景
数据结构稳定,但作用于数据结构的操作经常变化的场景。
需要将数据结构与数据操作分离的场景。
需要对不同数据类型进行操作,而不适用分支判断具体类型的场景。
元素具体类型并非单一,访问者均可操作的场景。
- 数据结构的操作分离:当有一个复杂的数据结构(如树形结构、图形系统中的图形集合等),并且需要对这个数据结构执行多种不同的操作(如计算、打印、转换等)时,访问者模式可以将操作代码从数据结构类中分离出来,使得数据结构的定义更加清晰,操作的扩展更加容易。
- 编译器设计:如前面提到的语法树遍历,用于语义分析、中间代码生成、代码优化等阶段。不同的编译器阶段可以定义不同的访问者来对语法树进行操作。
- XML文档处理:可以将XML文档看作是一个树形的数据结构,访问者模式可以用于对XML元素进行不同的操作,如验证、转换、提取信息等。
- 编译器构建:在编译器中,不同的节点类型(如表达式、语句等)可以通过访问者模式进行不同的处理,如语法检查、代码生成等。
- 文档处理:在文档处理系统中,不同的文档元素(如文本、图片、表格等)可以通过访问者模式进行不同的处理,如渲染、统计字数等。
- 图形界面工具:在图形界面工具中,不同的UI组件(如按钮、文本框、菜单等)可以通过访问者模式进行不同的操作,如绘制、事件处理等。
- 数据分析:在数据分析系统中,不同的数据结构(如树、图、表等)可以通过访问者模式进行不同的分析操作,如计算总和、平均值等。
- 游戏开发:在游戏开发中,不同的游戏对象(如玩家、敌人、道具等)可以通过访问者模式进行不同的操作,如更新状态、渲染图像等。
七、优缺点
优点:
- 分离操作和数据结构:使得数据结构的定义和操作的定义可以独立变化,提高了代码的可维护性和可扩展性。当需要添加新的操作时,只需要创建新的访问者类,而不需要修改数据结构类。
- 符合开闭原则:对于数据结构和操作的扩展是开放的,对于修改是封闭的。可以方便地添加新的元素(数据结构中的节点)和新的访问者(操作)。
- 增加代码的复用性:访问者类可以在多个不同的数据结构上复用,只要这些数据结构的元素接口是兼容的。
缺点:
- 增加了代码的复杂性:访问者模式需要定义多个接口和类,包括访问者接口、具体访问者类、元素接口、具体元素类和对象结构类等,这使得代码结构相对复杂,对于简单的应用场景可能会增加不必要的复杂性。
- 违背了迪米特法则:因为访问者模式需要访问数据结构中的元素,可能会导致访问者和元素之间的耦合度过高,访问者需要知道元素的内部结构和接口细节,这在一定程度上违背了迪米特法则(最少知识原则)。

相关文章:
设计模式 行为型 访问者模式(Visitor Pattern)与 常见技术框架应用 解析
访问者模式(Visitor Pattern)是一种行为设计模式,它允许你在不改变元素类的前提下定义作用于这些元素的新操作。这种模式将算法与对象结构分离,使得可以独立地变化那些保存在复杂对象结构中的元素的操作。 假设我们有一个复杂的对…...
golang之数据库操作
1.导入必要的包 import("database/sql"_ "github.com/go-sql-driver/mysql" //使用此作为数据库驱动 ) 2.相关操作 连接数据库 使用sql.Open()函数进行数据库的连接 db, err : sql.Open("mysql", "user:passwordtcp(127.0.0.1:3306)/db…...
对话新晋 Apache SeaTunnel Committer:张圣航的开源之路与技术洞察
近日,张圣航被推选为 Apache SeaTunnel 的 Committer成员。带着对技术的热情和社区的责任,他将如何跟随 Apache SeaTunnel 社区迈向新的高度?让我们一起来聆听他的故事。 自我介绍 请您简单介绍一下自己,包括职业背景、当前的工作…...
Mac 删除ABC 输入法
参考链接:百度安全验证 Mac下删除系统自带输入法ABC,正解!_mac删除abc输入法-CSDN博客 ABC 输入法和搜狗输入法等 英文有冲突~~ 切换后还会在英文状态,可以删除 ;可能会对DNS 输入有影响,但是可以通过复…...
《机器学习》之K-means聚类
目录 一、简介 二、K-means聚类实现步骤 1、初始化数据点、确定K值 2、通过距离分配数据点 3、更新簇中心 4、 迭代更新 三、聚类效果评价方式 1、轮廓系数的定义 2、整体轮廓系数 3、使用场景 4、优点 5、缺点 6、代码实现方法 四、K-means聚类代码实现 1、API接…...
日常工作之 Elasticsearch 常用查询语句汇总
日常工作之 Elasticsearch 常用查询语句汇总 查询现有索引创建索引查询索引结构插入数据查询索引数据查看索引磁盘占用信息删除索引查看分词器分词结果指定查询数量指定条件查询数据迁移统计索引数据量更新数据 在使用 es 的过程中,总是会用到 es 的查询语句&#x…...
WeakAuras NES Script(lua)
WeakAuras NES Script 修星脚本字符串 脚本1:NES !WA:2!TMZFWXX1zDxVAs4siiRKiBN4eV(sTRKZ5Z6opYbhQQSoPtsxr(K8ENSJtS50(J3D7wV3UBF7E6hgmKOXdjKsgAvZFaPTtte0mD60XdCmmecDMKruyykDcplAZiGPfWtSsag6myGuOuq89EVDV9wPvKeGBM7U99EFVVVV33VFFB8Z2TJ8azYMlZj7Ur3QDR(…...
JVM 触发类加载的条件有哪些?
目录 一、类加载生命周期 二、主动引用 2.1、创建类的实例 2.2、访问类的静态字段或静态方法 2.3、反射 2.4、初始化类的子类时,先初始化父类 2.5、虚拟机启动时,初始化 main 方法所在的类 2.6、动态语言支持 三、被动引用 3.1、通过子类引用父…...
Android实战经验篇-增加系统分区
系列文章转如下链接: Android Display Graphics系列文章-汇总 Android实战经验篇-系列文章汇总 本文主要包括部分: 一、Android分区说明 1.1 系统分区查看 1.2 分区表修改 1.3 验证新分区 二、源码修改 2.1 generate_extra_images 2.2 fstab 2…...
深入学习 Python 量化编程
深入学习 Python 量化编程 第一章:Python 基础与量化编程环境搭建 1.1 安装必要的库 首先,你需要安装一些在量化编程中常用的 Python 库。可以通过以下命令安装这些库: pip install numpy pandas matplotlib yfinance backtrader scikit-…...
机器学习笔记——特征工程
大家好,这里是好评笔记,公主号:Goodnote,专栏文章私信限时Free。本笔记介绍机器学习中常见的特征工程方法、正则化方法和简要介绍强化学习。 文章目录 特征工程(Fzeature Engineering)1. 特征提取ÿ…...
4种革新性AI Agent工作流设计模式全解析
文章目录 导读:AI Agent的四种关键设计模式如下:1. 反思2. 工具使用3. 规划4. 多Agent协作 总结内容简介: 导读: AI Agent是指能够在特定环境中自主执行任务的人工智能系统,不仅接收任务,还自主制定和执行…...
【入门级】计算机网络学习
网络安全:前端开发者必知:Web安全威胁——XSS与CSRF攻击及其防范-CSDN博客 三次握手四次挥手:前端网络—三次握手四次挥手_前端三次握手-CSDN博客 http协议和https协议的区别:前端网络—http协议和https协议的区别-CSDN博客 网…...
安装 Jenkins 后无法访问用户名或密码且忘记这些凭证怎么办?
Jenkins 是一款功能强大的自动化服务器,在持续集成与交付(CI/CD)领域应用广泛。不过,用户在使用过程中,尤其是首次接触该系统或系统重启后,常常会遇到登录方面的问题。要是 Jenkins 突然要求输入用户名和密…...
day08_Kafka
文章目录 day08_Kafka课程笔记一、今日课程内容一、消息队列(了解)**为什么消息队列就像是“数据的快递员”?****实际意义**1、产生背景2、消息队列介绍2.1 常见的消息队列产品2.2 应用场景2.3 消息队列中两种消息模型 二、Kafka的基本介绍1、…...
安装conda 环境
conda create -n my_unet5 python3.8 (必须设置3.8版本) conda activate my_unet5...
【dockerros2】ROS2节点通信:docker容器之间/docker容器与宿主机之间
🌀 一个中大型ROS项目常需要各个人员分别完成特定的功能,而后再组合部署,而各人员完成的功能常常依赖于一定的环境,而我们很难确保这些环境之间不会相互冲突,特别是涉及深度学习环境时。这就给团队项目的部署落地带来了…...
使用外网访问在群晖中搭建思源docker
还是要折腾,之前发现用公网IP可以访问就没有折腾,今天ip变了,用不了了,一搜,发现有方法可以用域名访问,哎,太好了! 原文:分享我在 群晖 docker 部署 思源笔记 步骤 - 链…...
深度学习中的EMA技术:原理、实现与实验分析
深度学习中的EMA技术:原理、实现与实验分析 1. 引言 指数移动平均(Exponential Moving Average, EMA)是深度学习中一种重要的模型参数平滑技术。本文将通过理论分析和实验结果,深入探讨EMA的实现和效果。 深度学习中的EMA技术:原理、实现与…...
win32汇编环境,窗口程序中对按钮控件常用操作的示例
;运行效果 ;win32汇编环境,窗口程序中对按钮控件常用操作的示例 ;常用的操作,例如创建按钮控件,使其无效,改变文本,得到文本等。 ;将代码复制进radasm软件里,直接就可以编译运行。重点部分加备注。 ;>&g…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...
