设计模式 行为型 访问者模式(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 {@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是元素接口,CircleRectangle是具体元素。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));

在这个例子中,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. 违背了迪米特法则:因为访问者模式需要访问数据结构中的元素,可能会导致访问者和元素之间的耦合度过高,访问者需要知道元素的内部结构和接口细节,这在一定程度上违背了迪米特法则(最少知识原则)。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++中引用参数与指针参数的区别与联系详解

在C++中,函数参数可以通过值传递、引用传递和指针传递。虽然指针传递在C和C++中都非常常见,但C++引入了引用类型,使得引用传递变得更加直接和易用。本文将详细介绍函数中引用参数和指针参数的区别与联系,并通过C++语言代码示例加以说明。 一、基本概念 值传递(Pass by Val…

初识JVM HotSopt 的发展历程

目录 导学 目前企业对程序员的基本要求 面向的对象 实战 学习目标 JVM 是什么 JVM 的三大核心功能 各大 JVM look 看一下虚拟机 HotSopt 的发展历程 总结 导学 目前企业对程序员的基本要求 面向的对象 实战 学习目标 JVM 是什么 JVM 的三大核心功能 即时编译 主要是…

html中鼠标位置信息

pageX&#xff1a;鼠标距离页面的最左边的距离&#xff0c;包括滚动条的长度。clientX&#xff1a;鼠标距离浏览器视口的左距离&#xff0c;不包括滚动条。offsetX&#xff1a;鼠标到事件源左边的距离。movementX&#xff1a;鼠标这次触发的事件的位置相对于上一次触发事件的位…

RabbitMQ 高可用方案:原理、构建与运维全解析

文章目录 前言&#xff1a;1 集群方案的原理2 RabbitMQ高可用集群相关概念2.1 设计集群的目的2.2 集群配置方式2.3 节点类型 3 集群架构3.1 为什么使用集群3.2 集群的特点3.3 集群异常处理3.4 普通集群模式3.5 镜像集群模式 前言&#xff1a; 在实际生产中&#xff0c;RabbitM…

【容器逃逸实践】挂载/dev方法

0、前置知识 怎么在容器里面执行命令&#xff0c; 有几种方法 # 不进入容器&#xff0c;创建并启动一个新的容器 $ docker run -itd --name ubuntu-test ubuntu /bin/bash # 进入容器&#xff0c;创建并启动一个新的容器 $ docker run -itd --name ubuntu-test ubuntu /bin…

linux: 文本编辑器vim

文本编辑器 vi的工作模式 (vim和vi一致) 进入vim的方法 方法一:输入 vim 文件名 此时左下角有 "文件名" 文件行数,字符数量 方法一: 输入 vim 新文件名 此时新建了一个文件并进入vim,左下角有 "文件名"[New File] 灰色的长方形就是光标,输入文字,左下…

Python爬虫-汽车之家各车系周销量榜数据

前言 本文是该专栏的第43篇,后面会持续分享python爬虫干货知识,记得关注。 在本专栏之前,笔者在文章《Python爬虫-汽车之家各车系月销量榜数据》中,有详细介绍,如何爬取“各车系车型的月销量榜单数据”的方法以及完整代码教学教程。 而本文,笔者同样以汽车之家平台为例,…

Python----Python高级(函数基础,形参和实参,参数传递,全局变量和局部变量,匿名函数,递归函数,eval()函数,LEGB规则)

一、函数基础 1.1、函数的用法和底层分析 函数是可重用的程序代码块。 函数的作用&#xff0c;不仅可以实现代码的复用&#xff0c;更能实现代码的一致性。一致性指的是&#xff0c;只要修改函数的代码&#xff0c;则所有调用该函数的地方都能得到体现。 在编写函数时&#xf…

欧拉路径算法

欧拉图&#xff1a; 对于应该连通图G&#xff0c;有&#xff1a; 1欧拉路径&#xff1a;一条路径&#xff0c;它能够不重复地遍历完所有的边&#xff0c;这个性质很像不重复地一笔画完所有边&#xff0c;所以有些涉及到欧拉路径的问题叫做一笔画问题。 2欧拉回路&#xff1a…

后端技术选型 sa-token校验学习 下 结合项目学习 后端鉴权

目录 后端注册拦截器 实现对 WebMvcConfigurer 接口的类实现 静态变量 方法重写 注册 Spring Framework拦截器 Sa-Token中SaServletFilter拦截器 思考 为什么使用两个拦截器 1. Spring Framework 拦截器 2. SaServletFilter 为什么要注册两个拦截器&#xff1f; 总结 …

Angular-生命周期及钩子函数

什么是生命周期 Angular 创建和渲染组件及其子组件&#xff0c;当它们绑定的属性发生变化时检查它们&#xff0c;并在从 DOM 中移除它之前销毁它们。生命周期函数通俗的讲就是组件创建、组件更新、组件销毁的时候会触发的一系列的方法。当 Angular 使用构造函数新建一个组件或…

Microsoft

Microsoft Word目录1.目录编号与文字的间距设置2. 目录编号缩进设置 Excel函数MID&#xff08;提取字符&#xff09;CONCAT&#xff08;组合字符串&#xff09;EXACT&#xff08;比较字符串&#xff09; PowerPointwindows 11 恢复右键传统菜单 Word 目录 1.目录编号与文字的…

MAC AndroidStudio模拟器无网络

先确认PC端是正常访问网络的&#xff1b; 模拟器端修改Wifi设置&#xff1a;设置 - 网络和互联网 - WALN设置 按照上图修改&#xff1b; IP设置&#xff1a;从DHCP修改为静态&#xff0c;IP地址&#xff1a;10.0.2.16 &#xff0c;网关&#xff1a;10.0.2.2 &#xff0c; DNS…

Android 对接口的封装使用

前言 本篇文章主要是记录Android代码 对java 接口的封装和使用方法&#xff0c;比较基础&#xff0c;记录一下&#xff0c;阅读本篇文章前&#xff0c;请移步 java基础系列(九) 接口和抽象类 这篇文章。 接口理解 从设计角度: 设计方面的区别 抽象类是对一种事物的抽象&#…

Qiskit快速编程探索(进阶篇)

五、量子电路模拟:探索量子世界的虚拟实验室 5.1 Aer模拟器:强大的模拟引擎 在量子计算的探索旅程中,Aer模拟器作为Qiskit的核心组件之一,宛如一座功能强大的虚拟实验室,为开发者提供了在经典计算机上模拟量子电路运行的卓越能力。它打破了硬件条件的限制,使得研究者无…

如何独立SDK模块到源码目录?

如何独立SDK模块到源码目录&#xff1f; 常见三种构建方式&#xff0c;具体取决于SDK开源程序库的方式&#xff1a; 类UNIX系统平台项目管理工具的进化路径&#xff1a;简单的Makefile>Configure(Autoconf/Automake)>CMake openWrt示例&#xff0c;如下&#xff1a; …

极客说|Azure AI Agent Service 结合 AutoGen/Semantic Kernel 构建多智能体解决⽅案

作者&#xff1a;卢建晖 - 微软高级云技术布道师 「极客说」 是一档专注 AI 时代开发者分享的专栏&#xff0c;我们邀请来自微软以及技术社区专家&#xff0c;带来最前沿的技术干货与实践经验。在这里&#xff0c;您将看到深度教程、最佳实践和创新解决方案。关注「极客说」&am…

MMDetection框架下的常见目标检测与分割模型综述与实践指南

目录 综述与实践指南 SSD (Single Shot MultiBox Detector) 基本配置和使用代码 RetinaNet 基本配置和使用代码 Faster R-CNN 基本配置和使用代码 Mask R-CNN 基本配置和使用代码 Cascade R-CNN 基本配置和使用代码 总结 综述与实践指南 MMDetection是一个基于Py…

服务器数据恢复—EMC存储POOL中数据卷被删除的数据恢复案例

服务器数据恢复环境&故障&#xff1a; EMC Unity 400存储连接了2台硬盘柜。2台硬盘柜上一共有21块硬盘&#xff08;520字节&#xff09;。21块盘组建了2组RAID6&#xff1a;一组有11块硬盘&#xff0c;一组有10块硬盘。 在存储运行过程中&#xff0c;管理员误操作删除了 2组…

Leetcode 377. 组合总和 Ⅳ 动态规划

原题链接&#xff1a;Leetcode 377. 组合总和 Ⅳ 可参考官解 class Solution { public:int combinationSum4(vector<int>& nums, int target) {vector<int> dp(target 1);dp[0] 1;// 总和为 i 的元素组合的个数for (int i 1; i < target; i) {// 每次都…