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

突破编程_C++_设计模式(访问者模式)

1 访问者模式的基本概念

C++中的访问者模式是一种行为设计模式,它允许你在不修改类层次结构的情况下增加新的操作。这种模式将数据结构与数据操作解耦,使得操作可以独立于对象的类来定义。

访问者模式的主要组成部分包括:

(1)访问者(Visitor): 这是一个接口,它声明了一个访问操作,该操作可以被应用到所有的元素上。访问操作的具体实现在访问者的子类中完成。

(2)元素(Element): 这是一个接口,它定义了一个接受操作,该操作可以被一个访问者访问。元素接口通常有一个接受访问者作为参数的接受方法。

(3)具体元素(Concrete Element): 这是实现元素接口的具体类,它实现了接受方法,该方法将调用访问者的访问方法。

(4)对象结构(Object Structure): 这是元素的集合,它以一种合适的方式包含元素。对象结构可以是一个简单的集合,也可以是一个复杂的树形结构。

2 访问者模式的实现步骤

访问者模式的实现步骤如下:

(1)定义访问者接口:

首先,需要定义一个访问者接口,这个接口声明了所有可能应用于元素对象的操作。这些操作通常作为纯虚函数存在,具体的操作实现将由具体的访问者类来完成。

(2)定义元素接口:

接下来,定义一个元素接口,这个接口声明了一个接受方法,该方法接受一个访问者对象作为参数。元素接口中的接受方法通常是虚函数,以便在元素的具体类中实现多态性。

(3)实现具体元素类:

然后,创建实现元素接口的具体元素类。这些类将包含数据,并实现接受方法,该方法将调用访问者的访问方法。

(4)实现具体的访问者类:

接着,创建实现访问者接口的具体访问者类。这些类将包含访问元素所需的具体逻辑。当访问者的访问方法被调用时,它将针对具体的元素对象执行相应的操作。

(5)创建对象结构:

创建一个对象结构,该结构负责管理元素对象的集合。这可以是一个简单的容器,如数组或向量,也可以是一个更复杂的结构,如树或图。

(6)使用访问者模式:

最后,在客户端代码中,创建具体的访问者对象,并通过对象结构访问元素对象。当需要执行某个操作时,通过对象结构的遍历方法,将具体的访问者对象传递给每个元素对象的接受方法。元素对象的接受方法将调用访问者的访问方法,从而执行相应的操作。

如下为样例代码:

#include <iostream>  
#include <vector>  
#include <memory>  class Element;// 步骤一:定义访问者接口  
class Visitor {
public:virtual ~Visitor() = default;virtual void visit(const std::shared_ptr<Element>& element) const = 0;
};// 步骤二:定义元素接口  
class Element : public std::enable_shared_from_this<Element> {
public:virtual ~Element() = default;virtual void accept(const std::shared_ptr<Visitor>& visitor) = 0;
};// 步骤三:实现具体元素类  
class ConcreteElement : public Element {
public:void accept(const std::shared_ptr<Visitor>& visitor) override {visitor->visit(shared_from_this());}void operation() const {std::cout << "ConcreteElement operation" << std::endl;}
};// 步骤四:实现具体的访问者类  
class ConcreteVisitor : public Visitor {
public:void visit(const std::shared_ptr<Element>& element) const override {auto concreteElement = std::dynamic_pointer_cast<ConcreteElement>(element);if (concreteElement) {concreteElement->operation();std::cout << "Visited by ConcreteVisitor" << std::endl;}else {std::cout << "Element is not of type ConcreteElement" << std::endl;}}
};// 步骤五:创建对象结构  
class ObjectStructure {
public:void attach(const std::shared_ptr<Element>& element) {m_elements.push_back(element);}void detach(const std::shared_ptr<Element>& element) {auto it = std::find(m_elements.begin(), m_elements.end(), element);if (it != m_elements.end()) {m_elements.erase(it);}}void accept(const std::shared_ptr<Visitor>& visitor) const {for (const auto& element : m_elements) {element->accept(visitor);}}private:std::vector<std::shared_ptr<Element>> m_elements;
};// 步骤六:使用访问者模式  
int main() 
{// 创建对象结构并添加元素  ObjectStructure objectStructure;objectStructure.attach(std::make_shared<ConcreteElement>());// 创建访问者  std::shared_ptr<Visitor> visitor = std::make_shared<ConcreteVisitor>();// 执行访问  objectStructure.accept(visitor);return 0;
}

上面代码的输出为:

ConcreteElement operation
Visited by ConcreteVisitor

上面的代码使用了 std::shared_ptr 智能指针来管理 Visitor 和 Element 对象的生命周期。std::dynamic_pointer_cast 用于安全地执行动态类型转换,以确认 Element 指针是否可以转换为 ConcreteElement 类型。如果转换成功,则执行相应的操作。

ObjectStructure 类负责管理 Element 对象的集合,并提供 attach 和 detach 方法来添加和删除元素。accept 方法则遍历所有元素,并将访问者传递给每个元素的 accept 方法,从而执行访问操作。

在 main 函数中,创建了一个 ObjectStructure 对象,并向其添加了一个 ConcreteElement 对象。然后,创建了一个 ConcreteVisitor 对象,并通过 ObjectStructure 的 accept 方法将访问者传递给所有元素。这样,就实现了访问者模式的使用。

3 访问者模式的应用场景

C++ 访问者模式的应用场景广泛,主要适用于以下情况:

(1)双层分派场景: 访问者模式实现了一种称为“双层分派”的机制。第一层分派发生在客户端代码中,当客户端将访问者对象传递给元素对象的 accept 方法时。第二层分派发生在元素对象的 accept 方法内部,它根据访问者的类型调用相应的访问方法。这种双层分派机制使得操作可以在元素对象的上下文中执行,并且可以根据元素的类型进行不同的处理。

(2)数据结构稳定但操作易变的场景: 如果数据结构相对稳定,但需要在其上执行的操作经常变化,访问者模式可以帮助将这些操作与数据结构解耦,使得操作的变化不会影响到数据结构的定义。

(3)操作需要扩展的场景: 当需要对一个对象结构中的元素执行多种不同的、不相关的操作时,且这些操作可能会在未来发生变化或增加时,使用访问者模式非常合适。通过将操作封装在访问者中,可以在不修改元素类的情况下添加新的操作。

(4)需要对对象结构中的对象进行不同操作的场景: 当需要在运行时决定对对象结构中的哪些元素执行哪些操作时,访问者模式可以很容易地实现这种动态行为。

(5)复杂的对象结构遍历: 当需要遍历一个复杂的对象结构(如树形结构、图结构等),并对结构中的每个元素执行特定的操作时,访问者模式可以简化代码结构,使得遍历和操作逻辑更加清晰和分离。

3.1 访问者模式应用于双层分派场景

双层分派允许根据对象类型和访问者类型动态地决定执行哪个操作。以下是一个简单的游戏场景,其中游戏角色可以被不同的访问者(例如渲染器或AI处理器)访问。

首先,定义访问者接口和元素接口:

#include <iostream>  
#include <memory>  
#include <vector>  
#include <string>  class Character;// 访问者接口  
class Visitor {
public:virtual ~Visitor() = default;virtual void visit(const std::shared_ptr<Character>& character) const = 0;
};// 元素接口  
class Character : public std::enable_shared_from_this<Character> {
public:virtual ~Character() = default;virtual void accept(const std::shared_ptr<Visitor>& visitor) = 0;virtual std::string getName() const = 0;
};

接着,定义具体的游戏角色类和访问者类:

// 具体游戏角色类A  
class Warrior : public Character {
public:std::string getName() const override { return "Warrior"; }void accept(const std::shared_ptr<Visitor>& visitor) override {visitor->visit(shared_from_this());}void fight() const {std::cout << getName() << " is fighting!" << std::endl;}
};// 具体游戏角色类B  
class Mage : public Character {
public:std::string getName() const override { return "Mage"; }void accept(const std::shared_ptr<Visitor>& visitor) override {visitor->visit(shared_from_this());}void castSpell() const {std::cout << getName() << " is casting a spell!" << std::endl;}
};// 具体访问者类:渲染器  
class Renderer : public Visitor {
public:void visit(const std::shared_ptr<Character>& character) const override {std::cout << "Rendering " << character->getName() << std::endl;}
};// 具体访问者类:AI处理器  
class AIProcessor : public Visitor {
public:void visit(const std::shared_ptr<Character>& character) const override {std::cout << "Processing AI for " << character->getName() << std::endl;// 这里可以根据角色类型执行不同的AI逻辑  }
};

最后,定义一个管理游戏角色的对象结构类,并使用访问者进行双层分派:

// 对象结构类:游戏世界  
class GameWorld {
public:void addCharacter(const std::shared_ptr<Character>& character) {m_characters.push_back(character);}void render(const std::shared_ptr<Visitor>& visitor) const {for (const auto& character : m_characters) {character->accept(visitor);}}private:std::vector<std::shared_ptr<Character>> m_characters;
};int main() 
{// 创建游戏角色  auto warrior = std::make_shared<Warrior>();auto mage = std::make_shared<Mage>();// 创建游戏世界并添加角色  GameWorld gameWorld;gameWorld.addCharacter(warrior);gameWorld.addCharacter(mage);// 创建渲染器访问者  auto renderer = std::make_shared<Renderer>();// 使用渲染器访问者渲染所有角色  gameWorld.render(renderer);// 创建AI处理器访问者  auto aiProcessor = std::make_shared<AIProcessor>();// 使用AI处理器访问者处理所有角色的AI  gameWorld.render(aiProcessor);// 不需要手动释放对象,智能指针会自动处理  return 0;
}

上面代码的输出为:

Rendering Warrior
Rendering Mage
Processing AI for Warrior
Processing AI for Mage

在这个示例中,Warrior 和 Mage 类继承了 Character 接口,并实现了各自的 accept 方法和特定行为(如 fight 和 castSpell)。Renderer 和 AIProcessor 类继承了 Visitor 接口,并实现了针对 Character 的 visit 方法。

GameWorld 类管理着游戏中的角色,并提供了 render 方法,该方法接受一个 Visitor 智能指针,并使用 accept 方法触发双层分派。当调用 gameWorld.render(renderer) 时,所有角色都会被渲染器访问,并调用它们各自的 accept 方法。由于 accept 方法内部调用了 visitor->visit(shared_from_this()),这就会触发对应的 visit 方法,在这里是 Renderer 类的 visit 方法,负责渲染角色。

3.2 访问者模式应用数据结构稳定但操作易变的场景

该场景是指:对于一组稳定的数据结构(元素),在这些数据结构上执行各种易变的操作(访问者)时,每个操作可能需要访问数据结构的不同部分,并且可能以不同的方式处理这些部分。

下面是一个使用访问者模式的示例,它模拟了一个简单的形状集合,其中形状是稳定的数据结构,而不同的操作(如计算面积、周长等)是易变的访问者。

首先,定义形状接口和访问者接口:

#include <iostream>  
#include <memory>  
#include <vector>  class Visitor;// 形状接口  
class Shape : public std::enable_shared_from_this<Shape> {
public:virtual ~Shape() = default;virtual void accept(const std::shared_ptr<Visitor>& visitor) = 0;
};class Circle;
class Rectangle;// 访问者接口  
class Visitor {
public:virtual ~Visitor() = default;virtual void visit(const std::shared_ptr<Circle>& circle) const = 0;virtual void visit(const std::shared_ptr<Rectangle>& rectangle) const = 0;
};

接着,定义具体的形状类和访问者类:

// 圆形类  
class Circle : public Shape {double radius;
public:Circle(double r) : radius(r) {}void accept(const std::shared_ptr<Visitor>& visitor) override {visitor->visit(std::dynamic_pointer_cast<Circle>(shared_from_this()));}double getRadius() const { return radius; }
};// 矩形类  
class Rectangle : public Shape {double width, height;
public:Rectangle(double w, double h) : width(w), height(h) {}void accept(const std::shared_ptr<Visitor>& visitor) override {visitor->visit(std::dynamic_pointer_cast<Rectangle>(shared_from_this()));}double getWidth() const { return width; }double getHeight() const { return height; }
};// 计算面积的访问者  
class AreaVisitor : public Visitor {
public:void visit(const std::shared_ptr<Circle>& circle) const override {std::cout << "Circle area: " << 3.14159 * circle->getRadius() * circle->getRadius() << std::endl;}void visit(const std::shared_ptr<Rectangle>& rectangle) const override {std::cout << "Rectangle area: " << rectangle->getWidth() * rectangle->getHeight() << std::endl;}
};// 计算周长的访问者  
class PerimeterVisitor : public Visitor {
public:void visit(const std::shared_ptr<Circle>& circle) const override {std::cout << "Circle perimeter: " << 2 * 3.14159 * circle->getRadius() << std::endl;}void visit(const std::shared_ptr<Rectangle>& rectangle) const override {std::cout << "Rectangle perimeter: " << 2 * (rectangle->getWidth() + rectangle->getHeight()) << std::endl;}
};

最后,创建一个管理形状的对象结构类,并使用访问者进行操作:

// 对象结构类:形状集合  
class ShapeCollection {
public:void addShape(const std::shared_ptr<Shape>& shape) {m_shapes.push_back(shape);}void process(const std::shared_ptr<Visitor>& visitor) const {for (const auto& shape : m_shapes) {shape->accept(visitor);}}private:std::vector<std::shared_ptr<Shape>> m_shapes;
};int main() 
{// 创建形状  auto circle = std::make_shared<Circle>(5.0);auto rectangle = std::make_shared<Rectangle>(4.0, 6.0);// 创建形状集合并添加形状  ShapeCollection collection;collection.addShape(circle);collection.addShape(rectangle);// 创建并使用面积访问者  auto areaVisitor = std::make_shared<AreaVisitor>();collection.process(areaVisitor);// 创建并使用周长访问者  auto perimeterVisitor = std::make_shared<PerimeterVisitor>();collection.process(perimeterVisitor);// 不需要手动释放对象,智能指针会自动处理  return 0;
}

上面代码的输出为:

Circle area: 78.5397
Rectangle area: 24
Circle perimeter: 31.4159
Rectangle perimeter: 20

在这个示例中,Circle 和 Rectangle 类继承了 Shape 接口,并实现了各自的 accept 方法和特定行为(半径以及长宽)。AreaVisitor 和 PerimeterVisitor 类继承了 Visitor 接口,并实现了计算圆形面积周长以及计算矩形面积周长的 visit 方法。随后在 ShapeCollection 的 process 进行访问调用。

4 访问者模式的优点与缺点

C++ 访问者模式的优点主要包括:

(1)扩展性好: 访问者模式使得在不修改已有类的情况下,可以添加新的操作。这意味着数据结构本身保持稳定,而新的操作可以很容易地添加到系统中。

(2)操作集中管理: 访问者模式将相关的操作集中到一个访问者类中,这有助于操作的封装和复用。

(3)双分派: 访问者模式通过对象的“接受”方法和访问者的“访问”方法实现了双分派,即运行时根据对象的实际类型和访问者的类型来确定执行的操作。

(4)灵活性: 访问者模式允许我们根据需要灵活地定义不同的访问者类,实现不同的操作逻辑。

(5)符合开闭原则: 访问者模式符合开闭原则,即对扩展开放,对修改封闭。当需要添加新的操作时,我们只需要添加新的访问者类,而不需要修改已有的数据结构。

然而,C++ 访问者模式也存在一些缺点:

(1)增加复杂性: 访问者模式增加了类的数量,使得系统变得更加复杂。每个元素类都需要实现接受方法,每个访问者类都需要实现访问方法,这可能导致代码量的增加。

(2)破坏封装性: 访问者模式要求元素类暴露其内部状态给访问者类,这可能会破坏元素的封装性。如果访问者类不恰当地使用这些内部状态,可能会导致错误或不可预见的行为。

(3)类型安全: 在访问者模式中,由于访问者类需要访问元素类的内部状态,因此需要确保类型安全。否则,可能会导致运行时错误。

(4)性能开销: 由于访问者模式涉及到双分派,因此在某些情况下可能会引入额外的性能开销。

相关文章:

突破编程_C++_设计模式(访问者模式)

1 访问者模式的基本概念 C中的访问者模式是一种行为设计模式&#xff0c;它允许你在不修改类层次结构的情况下增加新的操作。这种模式将数据结构与数据操作解耦&#xff0c;使得操作可以独立于对象的类来定义。 访问者模式的主要组成部分包括&#xff1a; &#xff08;1&…...

C语言入门到精通之练习53:矩阵交换行问题(附带源码)

描述 给定一个 5*5 的矩阵&#xff08;数学上&#xff0c;一个 rc 的矩阵是一个由 r 行 c 列元素排列成的矩形阵列&#xff09;&#xff0c;将第 n 行和第 m 行交换&#xff0c;输出交换后的结果。 输入输入共 6 行&#xff0c;前 5 行为矩阵的每一行元素, 元素与元素之间以一…...

Python白练-2统计下列5行字符串中字符出现的频数

问题&#xff1a;统计下列5行字符串中字符a、c、g、t出现的频数 数据&#xff1a;data2_2&#xff1a; 1.aggcacggaaaaacgggaataacggaggaggacttggcacggcattacacggagg 2.cggaggacaaacgggatggcggtattggaggtggcggactgttcgggga 3.gggacggatacggattctggccacggacggaaaggaggacacggcg…...

深入理解DHCP服务:网络地址的自动化分配

深入理解DHCP服务&#xff1a;网络地址的自动化分配 在现代网络环境中&#xff0c;动态主机配置协议&#xff08;DHCP&#xff09; 是一个至关重要的服务&#xff0c;它允许自动分配IP地址和其他相关配置信息给网络中的设备。本文将深入探讨DHCP服务的工作原理、配置方法以及如…...

Java高级编程—泛型

文章目录 1.为什么要有泛型 (Generic)1.1 泛型的概念1.2 使用泛型后的好处 2.在集合中使用泛型3.自定义泛型结构3.1 自定义泛型类、泛型接口3.2 自定义泛型方法 4.泛型在继承上的体现5.通配符的使用5.1 基本使用5.2 有限制的通配符的使用 1.为什么要有泛型 (Generic) Java中的…...

Exam in MAC [容斥]

题意 思路 正难则反 反过来需要考虑的是&#xff1a; (1) 所有满条件一的(x,y)有多少对&#xff1a; x 0 时&#xff0c;有c1对 x 1 时&#xff0c;有c对 ...... x c 时&#xff0c;有1对 以此类推 一共有 (c2)(c1)/2 对 (2) 符合 x y ∈ S的有多少对&#xff1a…...

Java 学习和实践笔记(36):接口(interface)

面向对象的精髓&#xff0c;最能体现这一点的就是接口&#xff01; 为什么我们讨论设计模式都只针对具备了抽象能力的语言&#xff08;比如C、Java、C#等)&#xff0c;就是因为设计模式所研究的&#xff0c;实际上就是如何合理的去抽象。 接口就是一组规范&#xff0c;所有实…...

Elastic Stack--10--QueryBuilders UpdateQuery

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 QueryBuildersESUtil QueryBuilders package com.elasticsearch; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.search.Sea…...

腾讯云服务器CVM_云主机_云计算服务器_弹性云服务器

腾讯云服务器CVM提供安全可靠的弹性计算服务&#xff0c;腾讯云明星级云服务器&#xff0c;弹性计算实时扩展或缩减计算资源&#xff0c;支持包年包月、按量计费和竞价实例计费模式&#xff0c;CVM提供多种CPU、内存、硬盘和带宽可以灵活调整的实例规格&#xff0c;提供9个9的数…...

Java八股文(Spring Boot)

Java八股文のSpring Boot Spring Boot Spring Boot 什么是Spring Boot&#xff1f; Spring Boot是一个用于开发和构建微服务应用程序的框架&#xff0c;它简化了Spring应用的配置和部署。 Spring Boot的核心特性是什么&#xff1f; Spring Boot的核心特性包括自动配置、起步依…...

ts文件怎么无损转换mp4?这样设置转换模式~

TS格式&#xff08;Transport Stream&#xff09;的起源可追溯到数字电视广播领域。设计初衷是解决视频、音频等多媒体数据在传输和存储中的问题。采用一系列标准技术&#xff0c;TS格式让视频信号能够以流的形式传输&#xff0c;因此在数字电视、广播等领域得到广泛应用。 MP4…...

如何在Windows 10上打开和关闭平板模式?这里提供详细步骤

前言 默认情况下&#xff0c;当你将可翻转PC重新配置为平板模式时&#xff0c;Windows 10会自动切换到平板模式。如果你希望手动打开或关闭平板模式&#xff0c;有几种方法可以实现。​ 自动平板模式在Windows 10上如何工作 如果你使用的是二合一可翻转笔记本电脑&#xff0…...

介绍kafka核心原理及底层刷盘机制,集群分片机制,消息丢失和重复消费有对应的线上解决方案

Kafka是一个高性能、分布式、持久化的消息系统&#xff0c;它的核心原理包括发布/订阅模型、分布式日志存储和高吞吐量的数据流处理。 发布/订阅模型&#xff1a;Kafka采用发布/订阅模型&#xff0c;消息的生产者将消息发送到一个或多个主题&#xff08;Topic&#xff09;&…...

基于Python的中医药知识问答系统设计与实现

[简介] 这篇文章主要介绍了基于Python的中医药知识问答系统的设计与实现。该系统利用Python编程语言&#xff0c;结合中医药领域的知识和技术&#xff0c;实现了一个功能强大的问答系统。文章首先介绍了中医药知识的特点和传统问答系统的局限性&#xff0c;然后提出了设计思路…...

QT 如何防止 QTextEdit 自动滚动到最下方

在往QTextEdit里面append字符串时&#xff0c;如果超出其高度&#xff0c;默认会自动滚动到QTextEdit最下方。但是有些场景可能想从文本最开始的地方展示&#xff0c;那么就需要禁止自动滚动。 我们可以在append之后&#xff0c;添加如下代码&#xff1a; //设置编辑框的光标位…...

【C/C++ 学习笔记】指针

【C/C 学习笔记】指针 视频地址: Bilibili 概念 可以通过指针间接访问内存用于保存地址 使用 通过 & 可以获取数据的指针 通过 * 可以取得指针的数据 指针的数据类型就是 数据类型 * int number 10;int *p &number;// 10 cout << "number: " …...

【Node.js从基础到高级运用】十二、身份验证与授权:JWT

身份验证与授权是现代Web应用中不可或缺的部分。了解如何在Node.js应用中实施这些机制&#xff0c;将使你能够构建更安全、更可靠的应用程序。本文将引导你通过使用JWT实现用户注册、登录和权限控制的过程。 JWT&#xff08;Json Web Token&#xff09; JWT是一种用于双方之间…...

蓝桥杯刷题|01入门真题

[蓝桥杯 2020 省 AB1] 解码 题目描述 小明有一串很长的英文字母&#xff0c;可能包含大写和小写。 在这串字母中&#xff0c;有很多连续的是重复的。小明想了一个办法将这串字母表达得更短&#xff1a;将连续的几个相同字母写成字母 出现次数的形式。 例如&#xff0c;连续…...

Python Django相关解答

问题&#xff1a;什么是django&#xff1f; Django是一个开源的高级web框架&#xff0c;皆在快速开发安全可维护的网站。他鼓励快速开发&#xff0c;并遵循“don’t repeat yourself”DRY原则 Django的MTV架构是什么 Django遵循MTV(模型-模板-试图)架构模式。模型&#xff08;…...

在Linux/Ubuntu/Debian中使用7z压缩和解压文件

要在 Ubuntu 上使用 7-Zip 创建 7z 存档文件&#xff0c;你可以使用“7z”命令行工具。 操作方法如下&#xff1a; 安装 p7zip&#xff1a; 如果你尚未在 Ubuntu 系统上安装 p7zip&#xff08;7-Zip 的命令行版本&#xff09;&#xff0c;你可以使用以下命令安装它&#xff1a;…...

设计一些策略和技术来防止恶意爬虫

当涉及到反爬虫时&#xff0c;我们需要设计一些策略和技术来防止恶意爬虫访问我们的网站。以下是一个简单的反爬虫框架示例&#xff0c;供您参考&#xff1a; import requests from bs4 import BeautifulSoup import timeclass AntiScrapingFramework:def __init__(self, targ…...

elasticsearch常见问题:xpack.security.transport.ssl、unknown setting [node.master]

文章目录 引言I 安装elasticsearch1.1 安装Master Node1.2 安装Slave nodeII elasticsearch常见问题2.1 invalid configuration for xpack.security.transport.ssl2.2 server ssl configuration requires a key and certificate2.3 unknown setting [node.master]III Kibana启动…...

LLM(大语言模型)——Springboot集成文心一言、讯飞星火、通义千问、智谱清言

目录 引言 代码完整地址 入参 出参 Controller Service Service实现类 模型Service 入参转换类 文心一言实现类 讯飞星火实现类 通义千问实现类 智谱清言实现类 引言 本文将介绍如何使用Java语言&#xff0c;结合Spring Boot框架&#xff0c;集成国内热门大模型API&am…...

什么是堆?什么是栈?

在计算机科学中&#xff0c;"堆&#xff08;heap&#xff09;"和"栈&#xff08;stack&#xff09;"是两种用于存储数据的数据结构&#xff0c;它们在内存管理中扮演着不同的角色。 堆&#xff08;Heap&#xff09;&#xff1a; 动态分配内存&#xff1a…...

【镜像转存】利用交互式学习平台killercoda转存K8S镜像至Docker私人仓库

文章目录 1. 镜像转存需求2. 注册并登陆 killercoda URL3. 打开playground4. 在线拉取K8S镜像并打上标签5. 推送K8S镜像到Docker私有仓库6. 登陆Docker私有仓库查看 1. 镜像转存需求 因K8S镜像在不开代理的情况下&#xff0c;拉取超时、下载缓慢&#xff0c;导致镜像拉取不下来…...

ov多域名SSL数字证书1200元一年送一月

随着互联网的发展&#xff0c;不论是个人用户还是企事业单位都不止有一个网站&#xff0c;为了保护网站安全&#xff0c;就需要为网站安装SSL证书&#xff0c;而SSL证书中的通配符SSL证书和多域名SSL证书都可以同时保护多个域名站点。其中&#xff0c;多域名SSL证书可以同时保护…...

MySQL 系统变量查看与设置(System Variables Configuration)

MySQL中有大量的系统变量控制服务器的行为&#xff0c;大部分的系统变量是不需要我们调整的&#xff0c;保持默认即可。但为了获得更高的性能和稳定性&#xff0c;有时需要适当对部分变量进行调整&#xff0c;本文总结了MySQL中系统变量的查看与设置方法。 目录 一、变量的类型…...

【Docker】apache 容器化部署

Apache环境标准软件基于Bitnami apache 构建。当前版本为2.4.58 你可以通过轻云UC部署工具直接安装部署&#xff0c;也可以手动按如下文档操作&#xff0c;该项目已经全面开源&#xff0c;可以从如下环境获取 配置文件地址: https://gitee.com/qingplus/qingcloud-platform Q…...

基于element-plus +腾讯云COS实现图片上传

① 首先基于element-plus里面的:http-request"upload"自定义封装事件写一个点击事件之后基于腾讯云的 登录 对象存储控制台 &#xff0c;创建存储桶。获取存储桶名称和 地域名称登录 访问管理控制台 &#xff0c;获取您的项目 SecretId 和 SecretKey。在项目中安装 …...

Kafka模拟器产生数据仿真-集成StructuredStreaming做到”毫秒“级实时响应StreamData落地到mysql

这是仿真过程某图&#xff1a; 仿真实战kafka kafka消费sink端和StructuredStreaming集成通信成功 &#xff0c; 数据接收全部接收 数据落地情况&#xff1a; 全部接收到并all存入mysql 下面就简单分享一下StructuredStreaming代码吧 import org.apache.spark.sql.function…...