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

在这里插入图片描述

访问者模式(Visitor Pattern)是一种行为设计模式,它允许你在不改变元素类的前提下定义作用于这些元素的新操作。这种模式将算法与对象结构分离,使得可以独立地变化那些保存在复杂对象结构中的元素的操作。

假设我们有一个复杂的对象结构,例如一个包含多种图形(圆形、矩形、三角形)的绘图系统。我们可能需要对这些图形进行多种操作,如计算面积、绘制轮廓、计算周长等。如果将这些操作的代码都放在图形类中,会使图形类变得非常臃肿。访问者模式就像是一个外来的“访问者”,它可以独立于图形类定义这些操作,然后在需要的时候“访问”图形并执行相应的操作。

一、核心思想

核心思想是将算法从对象的结构中分离出来,封装在独立的访问者对象中。这样一来,就可以在不修改对象结构的情况下,为该结构中的元素添加新的操作或行为。

二、定义与结构

  • 定义:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
  • 结构
    • 访问者(Visitor):抽象类或者接口,定义了对每个具体元素访问的操作方法。
    • 具体访问者(ConcreteVisitor):实现访问者接口,实现对具体元素的操作。
    • 元素(Element):抽象类或者接口,定义了一个接受访问者的方法(accept方法)。
    • 具体元素(ConcreteElement):实现元素接口,在accept方法中调用访问者对应的操作方法。
    • 对象结构(ObjectStructure):包含可以被访问的元素集合,提供方法让访问者访问它的元素。

三、角色

  • 访问者(Visitor)
    • 这是一个抽象角色,用于声明访问具体元素的方法。例如,在图形系统中,它可能有visitCirclevisitRectangle等方法,这些方法的参数通常是对应的具体元素。它定义了对不同类型元素进行操作的统一接口。
  • 具体访问者(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 {
    @Override
    public void visitCircle(Circle circle) {
        double area = Math.PI * circle.getRadius() * circle.getRadius();
        System.out.println("圆形面积:" + area);
    }
    @Override
    public 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;
    }
    @Override
    public 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;
    }
    @Override
    public 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是元素接口,CircleRectangle是具体元素。ShapeList是对象结构,用于管理图形对象。在main方法中,我们创建了图形对象列表,添加了圆形和矩形对象,然后创建了面积计算访问者,并让对象结构接受访问者来计算每个图形的面积。

五、常见技术框架应用

1、编译器中的语法树遍历

  • 在编译器开发中,语法树是一个复杂的对象结构。访问者模式可以用于遍历语法树并执行语义分析或代码生成等操作。
  • 步骤一:定义语法树节点(元素)接口和具体节点类
// 语法树节点接口
interface ASTNode {
    void accept(ASTVisitor visitor);
}
// 具体节点类(表达式节点)
class ExpressionNode implements ASTNode {
    // 表达式内容等属性
    @Override
    public void accept(ASTVisitor visitor) {
        visitor.visitExpressionNode(this);
    }
}
// 具体节点类(语句节点)
class StatementNode implements ASTNode {
    // 语句内容等属性
    @Override
    public void accept(ASTVisitor visitor) {
        visitor.visitStatementNode(this);
    }
}
  • 步骤二:定义访问者接口和具体访问者类(语义分析访问者)
// 访问者接口
interface ASTVisitor {
    void visitExpressionNode(ExpressionNode node);
    void visitStatementNode(StatementNode node);
}
// 具体访问者类(语义分析)
class SemanticAnalysisVisitor implements ASTVisitor {
    @Override
    public void visitExpressionNode(ExpressionNode node) {
        // 进行表达式语义分析,如检查操作数类型等
    }
    @Override
    public 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));

在这个例子中,ValidatorVisitorSerializerVisitor是具体的访问者,它们实现了针对不同类型UI组件的不同行为。UIComponent及其子类作为具体元素,提供了accept方法以接受访问者的访问。这种方式使得我们可以很容易地添加新的操作类型,而无需修改现有的UI组件类。

React 中的虚拟 DOM 遍历与更新(间接体现访问者模式思想)

  • 背景
    在 React 中,虚拟 DOM(Virtual DOM)是一个关键概念。它是真实 DOM 结构在 JavaScript 对象层面的一种表示,通过对比虚拟 DOM 的前后状态变化来决定如何高效地更新真实 DOM。
  • 分析
    • 元素(类似访问者模式中的元素角色):React 组件对应的虚拟 DOM 节点可以看作是元素。例如,一个简单的 <div> 组件在虚拟 DOM 里会被表示成一个包含各种属性(如 propschildren 等)的 JavaScript 对象,它定义了 accept(这里没有显式的 accept 方法名,但有类似机制)操作,也就是允许 React 的更新机制来处理它。
    • 访问者(类似访问者模式中的访问者角色):React 的 Diffing 算法(用于对比新旧虚拟 DOM 差异的机制)以及后续的 Reconciliation 过程(协调更新的过程)可以看作是访问者。Diffing 算法会遍历虚拟 DOM 树(从根节点开始),访问每个虚拟 DOM 节点(元素),去判断节点的类型、属性以及子节点等是否发生了变化,这个过程就类似访问者对不同元素进行访问并执行相应操作。例如,当检测到一个 <div> 组件的 props 发生了改变,访问者(更新机制)就会执行对应的更新真实 DOM 中该 <div> 对应部分的操作,比如更新 style 属性或者 innerHTML 等。
    • 具体过程示例
      假如有一个简单的 React 组件结构如下:
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-ifv-for 等)时运用了类似访问者模式的思路。
  • 分析
    • 元素(类似访问者模式中的元素角色):模板中的 HTML 标签以及文本节点等可以看作是元素。例如 <div v-if="show">{{ message }}</div> 中的 <div> 标签、文本插值 {{ message }} 等,它们构成了整个模板这个“数据结构”,并且每个元素都能被访问处理。
    • 访问者(类似访问者模式中的访问者角色):Vue 的模板编译器就是访问者。它会对模板这个元素集合进行遍历,解析每个元素。比如,对于指令类的元素,像遇到 v-if 指令时,访问者(编译器)会解析出条件判断逻辑,根据对应的数据(show 变量的值)来决定是否生成该 <div> 元素的渲染代码;对于文本插值元素 {{ message }},访问者会解析出需要将对应的数据(message 值)渲染到此处的操作。
    • 具体过程示例
      假设我们有如下 Vue 模板:
<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 对象(包含 titledescription 等属性)中获取相应的值,然后将其渲染到对应的 HTML 标签内,生成最终的 DOM 结构展示给用户。当组件的 titledescription 属性值发生变化时,更新机制又会作为访问者再次访问这些元素,重新获取新值并更新 DOM 展示。

总之,在前端框架中,访问者模式(或其类似思路)常被用于高效地处理页面元素的渲染、更新以及对模板、DOM 相关结构的操作,使得代码结构更清晰,便于扩展和维护不同的功能逻辑。

六、应用场景

数据结构稳定,但作用于数据结构的操作经常变化的场景。
需要将数据结构与数据操作分离的场景。
需要对不同数据类型进行操作,而不适用分支判断具体类型的场景。
元素具体类型并非单一,访问者均可操作的场景。
  1. 数据结构的操作分离:当有一个复杂的数据结构(如树形结构、图形系统中的图形集合等),并且需要对这个数据结构执行多种不同的操作(如计算、打印、转换等)时,访问者模式可以将操作代码从数据结构类中分离出来,使得数据结构的定义更加清晰,操作的扩展更加容易。
  2. 编译器设计:如前面提到的语法树遍历,用于语义分析、中间代码生成、代码优化等阶段。不同的编译器阶段可以定义不同的访问者来对语法树进行操作。
  3. XML文档处理:可以将XML文档看作是一个树形的数据结构,访问者模式可以用于对XML元素进行不同的操作,如验证、转换、提取信息等。
  4. 编译器构建:在编译器中,不同的节点类型(如表达式、语句等)可以通过访问者模式进行不同的处理,如语法检查、代码生成等。
  5. 文档处理:在文档处理系统中,不同的文档元素(如文本、图片、表格等)可以通过访问者模式进行不同的处理,如渲染、统计字数等。
  6. 图形界面工具:在图形界面工具中,不同的UI组件(如按钮、文本框、菜单等)可以通过访问者模式进行不同的操作,如绘制、事件处理等。
  7. 数据分析:在数据分析系统中,不同的数据结构(如树、图、表等)可以通过访问者模式进行不同的分析操作,如计算总和、平均值等。
  8. 游戏开发:在游戏开发中,不同的游戏对象(如玩家、敌人、道具等)可以通过访问者模式进行不同的操作,如更新状态、渲染图像等。

七、优缺点

优点

  1. 分离操作和数据结构:使得数据结构的定义和操作的定义可以独立变化,提高了代码的可维护性和可扩展性。当需要添加新的操作时,只需要创建新的访问者类,而不需要修改数据结构类。
  2. 符合开闭原则:对于数据结构和操作的扩展是开放的,对于修改是封闭的。可以方便地添加新的元素(数据结构中的节点)和新的访问者(操作)。
  3. 增加代码的复用性:访问者类可以在多个不同的数据结构上复用,只要这些数据结构的元素接口是兼容的。

缺点

  1. 增加了代码的复杂性:访问者模式需要定义多个接口和类,包括访问者接口、具体访问者类、元素接口、具体元素类和对象结构类等,这使得代码结构相对复杂,对于简单的应用场景可能会增加不必要的复杂性。
  2. 违背了迪米特法则:因为访问者模式需要访问数据结构中的元素,可能会导致访问者和元素之间的耦合度过高,访问者需要知道元素的内部结构和接口细节,这在一定程度上违背了迪米特法则(最少知识原则)。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/953579.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

继承多态语法糖

抽象类(通用) 子类继承父类方法后&#xff0c;这个子类对象如果执行方法的话&#xff0c;只要子类重写了就执行子类的&#xff0c;不执行父类的。 /*** 功能&#xff1a;* 作者&#xff1a;IT伟* 日期&#xff1a;2025/1/13 19:20*/ // 抽象类 A abstract class A {// 构造函…

MarS:一个由生成基础模型驱动的金融市场模拟引擎

“MARS: A FINANCIAL MARKET SIMULATION ENGINE POWERED BY GENERATIVE FOUNDATION MODEL” 项目主页&#xff1a;https://mars-lmm.github.io/ 论文地址&#xff1a;https://arxiv.org/pdf/2409.07486 Github地址&#xff1a;https://github.com/microsoft/MarS/ 摘要 生成…

macOS 使用 FreeRDP 远程访问 Windows:完整指南20250109

&#x1f5a5;️ macOS 使用 FreeRDP 远程访问 Windows&#xff1a;完整指南 引言 随着远程办公需求的快速增长&#xff0c;跨平台远程管理已经成为不可或缺的技能之一。作为一款开源轻量的远程桌面协议实现工具&#xff0c;FreeRDP 为 macOS 用户提供了一个简单、高效的解决…

两分钟解决 :![rejected] master -> master (fetch first) , 无法正常push到远端库

目录 分析问题的原因解决 分析问题的原因 在git push的时候莫名遇到这种情况 若你在git上修改了如README.md的文件。由于本地是没有README.md文件的&#xff0c;所以导致 远端仓库git和本地不同步。 将远端、本地进行合并就可以很好的解决这个问题 注意&#xff1a;直接git pu…

计算机图形学【绘制立方体和正六边形】

工具介绍 OpenGL&#xff1a;一个跨语言的图形API&#xff0c;用于渲染2D和3D图形。它提供了绘制图形所需的底层功能。 GLUT&#xff1a;OpenGL的一个工具库&#xff0c;简化了窗口创建、输入处理和其他与图形环境相关的任务。 使用的函数 1. glClear(GL_COLOR_BUFFER_BIT |…

springboot高校教室资源管理平台

Spring Boot高校教室资源管理平台是一个基于Spring Boot框架开发的高校教室资源管理系统。 一、平台背景与意义 随着高校规模的不断扩大&#xff0c;教室资源的管理变得日益复杂。传统的管理方式往往依赖于人工记录和纸质文件&#xff0c;不仅效率低下&#xff0c;而且容易出…

[笔记] 使用 Jenkins 实现 CI/CD :从 GitLab 拉取 Java 项目并部署至 Windows Server

随着软件开发节奏的加快&#xff0c;持续集成&#xff08;CI&#xff09;和持续部署&#xff08;CD&#xff09;已经成为确保软件质量和加速产品发布的不可或缺的部分。Jenkins作为一款广泛使用的开源自动化服务器&#xff0c;为开发者提供了一个强大的平台来实施这些实践。然而…

正点原子STM32F103战舰版电容触摸键学习

一、tpad.h代码 #ifndef __TPAD_H #define __TPAD_H#include "./SYSTEM/sys/sys.h"/******************************************************************************************/ /* TPAD 引脚 及 定时器 定义 *//* 我们使用定时器的输入捕获功能, 对TPAD进行检…

JVM:ZGC详解(染色指针,内存管理,算法流程,分代ZGC)

1&#xff0c;ZGC&#xff08;JDK21之前&#xff09; ZGC 的核心是一个并发垃圾收集器&#xff0c;所有繁重的工作都在Java 线程继续执行的同时完成。这极大地降低了垃圾收集对应用程序响应时间的影响。 ZGC为了支持太字节&#xff08;TB&#xff09;级内存&#xff0c;设计了基…

zerox - 使用视觉模型将 PDF 转换为 Markdown

7900 Stars 478 Forks 39 Issues 17 贡献者 MIT License Python 语言 代码: https://github.com/getomni-ai/zerox 主页: OmniAI. Automate document workflows 更多AI开源软件&#xff1a;AI开源 - 小众AI zerox基于视觉模型 API 服务&#xff0c;提供了将 PDF 文档转化为 Mar…

JAVA:Spring Boot 集成 JWT 实现身份验证的技术指南

1、简述 在现代Web开发中&#xff0c;安全性尤为重要。为了确保用户的身份&#xff0c;JSON Web Token&#xff08;JWT&#xff09;作为一种轻量级且无状态的身份验证方案&#xff0c;广泛应用于微服务和分布式系统中。本篇博客将讲解如何在Spring Boot 中集成JWT实现身份验证…

[论文阅读] (35)TIFS24 MEGR-APT:基于攻击表示学习的高效内存APT猎杀系统

《娜璋带你读论文》系列主要是督促自己阅读优秀论文及听取学术讲座&#xff0c;并分享给大家&#xff0c;希望您喜欢。由于作者的英文水平和学术能力不高&#xff0c;需要不断提升&#xff0c;所以还请大家批评指正&#xff0c;非常欢迎大家给我留言评论&#xff0c;学术路上期…

目标检测中的Bounding Box(边界框)介绍:定义以及不同表示方式

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

openEuler22.03系统使用Kolla-ansible搭建OpenStack

Kolla-ansible 是一个利用 Ansible 自动化工具来搭建 OpenStack 云平台的开源项目&#xff0c;它通过容器化的方式部署 OpenStack 服务&#xff0c;能够简化安装过程、提高部署效率并增强系统的可维护性。 前置环境准备&#xff1a; 系统:openEuler-22.03-LTS-SP4 配置&…

Leecode刷题C语言之统计重新排列后包含另一个字符串的子字符串数目②

执行结果:通过 执行用时和内存消耗如下&#xff1a; void update(int *diff, int c, int add, int *cnt) {diff[c] add;if (add 1 && diff[c] 0) {// 表明 diff[c] 由 -1 变为 0(*cnt)--;} else if (add -1 && diff[c] -1) {// 表明 diff[c] 由 0 变为 -…

uniapp 微信小程序webview与h5双向实时通信交互

描述&#xff1a; 小程序webview内嵌的h5需要向小程序实时发送消息&#xff0c;有人说postMessage可以实现&#xff0c;所以试验一下&#xff0c;结果是实现不了实时&#xff0c;只能在特定时机后退、组件销毁、分享时小程序才能接收到信息&#xff08;小程序为了安全等考虑做了…

pycharm-pyspark 环境安装

1、环境准备&#xff1a;java、scala、pyspark、python-anaconda、pycharm vi ~/.bash_profile export SCALA_HOME/Users/xunyongsun/Documents/scala-2.13.0 export PATH P A T H : PATH: PATH:SCALA_HOME/bin export SPARK_HOME/Users/xunyongsun/Documents/spark-3.5.4-bin…

fast-crud select下拉框 实现多选功能及下拉框数据动态获取(通过接口获取)

教程 fast-crud select示例配置需求:需求比较复杂 1. 下拉框选项需要通过后端接口获取 2. 实现多选功能 由于这个前端框架使用逻辑比较复杂我也是第一次使用,所以只记录核心问题 环境:vue3,typescript,fast-crud ,elementPlus 效果 代码 // crud.tsx文件(/.ts也行 js应…

高性能现代PHP全栈框架 Spiral

概述 Spiral Framework 诞生于现实世界的软件开发项目是一个现代 PHP 框架&#xff0c;旨在为更快、更清洁、更卓越的软件开发提供动力。 特性 高性能 由于其设计以及复杂精密的应用服务器&#xff0c;Spiral Framework框架在不影响代码质量以及与常用库的兼容性的情况下&a…

天机学堂笔记1

FeignClient(contextId "course", value "course-service") public interface CourseClient {/*** 根据老师id列表获取老师出题数据和讲课数据* param teacherIds 老师id列表* return 老师id和老师对应的出题数和教课数*/GetMapping("/course/infoB…