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

C++ 设计模式——策略模式

策略模式

    • 策略模式
      • 主要组成部分
      • 例一:逐步重构并引入策略模式
        • 第一步:初始实现
        • 第二步:提取共性并实现策略接口
        • 第三步:实现具体策略类
        • 第四步:实现上下文类
        • 策略模式 UML 图
          • 策略模式的 UML 图解析
      • 例二:逐步重构并引入策略模式
        • 第一步:初始实现
        • 第二步:提取共性并实现策略接口
        • 第三步:实现具体策略类
        • 第四步:实现上下文类:
        • 第五步:更新主函数
      • 策略模式 UML 图
        • 策略模式的 UML 图解析
      • 策略模式优缺点
      • 策略模式适用场景
      • 例一的完整代码
      • 例二的完整代码

策略模式

策略模式是一种行为设计模式,它定义了一系列算法,将每一个算法封装起来,并使它们可以互换。策略模式让算法的变化独立于使用算法的客户。

引入"策略“设计模式的定义:定义一些列算法类(策略类),将每个算法封装起来,让他们可以互相替换。换句话说,策略模式通常把一系列算法封装到一系列具体策略类中作为抽象策略类的字类,然后根据实际需要适用这些字类。

主要组成部分

  • 策略接口 (Strategy):定义一个统一的接口,声明所有支持的算法(策略)的方法。客户端通过这个接口调用具体策略。

  • 具体策略类 (Concrete Strategy):实现策略接口,定义具体的算法或行为。每个具体策略类实现不同的算法。

  • 上下文类 (Context):持有对策略接口的引用,负责调用具体策略的方法。上下文类可以在运行时动态地切换策略。

例一:逐步重构并引入策略模式

假设我们需要实现不同的排序算法(如冒泡排序和快速排序)。最初的实现可能是重复的代码。逐步重构的过程如下:

第一步:初始实现

为每种排序算法编写独立的处理逻辑:

#include <iostream>
#include <vector>void bubbleSort(std::vector<int>& arr) {for (size_t i = 0; i < arr.size() - 1; ++i) {for (size_t j = 0; j < arr.size() - i - 1; ++j) {if (arr[j] > arr[j + 1]) {std::swap(arr[j], arr[j + 1]);}}}
}void quickSort(std::vector<int>& arr, int low, int high) {if (low < high) {int pivot = arr[high];int i = low - 1;for (int j = low; j < high; ++j) {if (arr[j] < pivot) {++i;std::swap(arr[i], arr[j]);}}std::swap(arr[i + 1], arr[high]);quickSort(arr, low, i);quickSort(arr, i + 2, high);}
}int main() {std::vector<int> data = {5, 3, 8, 6, 2};bubbleSort(data);// 或者使用 quickSort(data, 0, data.size() - 1);return 0;
}
第二步:提取共性并实现策略接口

识别出排序的共性步骤,并创建一个策略接口 SortStrategy,定义排序方法:

class SortStrategy {
public:virtual void sort(std::vector<int>& arr) = 0; // 策略接口
};
第三步:实现具体策略类

为每种排序算法实现具体策略类,重写排序方法:

class BubbleSort : public SortStrategy {
public:void sort(std::vector<int>& arr) override {for (size_t i = 0; i < arr.size() - 1; ++i) {for (size_t j = 0; j < arr.size() - i - 1; ++j) {if (arr[j] > arr[j + 1]) {std::swap(arr[j], arr[j + 1]);}}}}
};class QuickSort : public SortStrategy {
public:void sort(std::vector<int>& arr) override {quickSort(arr, 0, arr.size() - 1);}private:void quickSort(std::vector<int>& arr, int low, int high) {if (low < high) {int pivot = arr[high];int i = low - 1;for (int j = low; j < high; ++j) {if (arr[j] < pivot) {++i;std::swap(arr[i], arr[j]);}}std::swap(arr[i + 1], arr[high]);quickSort(arr, low, i);quickSort(arr, i + 2, high);}}
};
第四步:实现上下文类

创建一个上下文类 Sorter,用于使用策略:

class Sorter {
private:SortStrategy* strategy;public:Sorter(SortStrategy* strategy) : strategy(strategy) {}void setStrategy(SortStrategy* strategy) {this->strategy = strategy;}void sort(std::vector<int>& arr) {strategy->sort(arr);}
};
策略模式 UML 图

策略模式 UML 图1

策略模式的 UML 图解析
  • 上下文类 (Context)

    • Sorter:它是上下文类,负责使用策略并持有策略的引用。Sorter 类通过 setStrategy 方法设置具体的排序策略,并通过 sort 方法调用该策略进行排序。
  • 抽象策略类 (Strategy)

    • SortStrategy:这是策略接口,定义了一个公共方法 sort,该方法由具体策略类实现。它确保所有具体策略类都有一致的接口。
  • 具体策略类 (Concrete Strategy)

    • BubbleSort:实现了 SortStrategy 接口,提供了冒泡排序的具体实现。
    • QuickSort:实现了 SortStrategy 接口,提供了快速排序的具体实现。

例二:逐步重构并引入策略模式

第一步:初始实现

首先,从一个简单的实现开始,其中战斗者类直接实现道具使用逻辑。

#include <iostream>
using namespace std;class Fighter {
public:Fighter(int life) : m_life(life) {}void UseBXD() { // 使用补血丹m_life += 200;cout << "使用补血丹,生命值增加200。" << endl;}void UseDHD() { // 使用大还丹m_life += 300;cout << "使用大还丹,生命值增加300。" << endl;}void UseSHD() { // 使用守护丹m_life += 500;cout << "使用守护丹,生命值增加500。" << endl;}int GetLife() {return m_life;}private:int m_life;
};int main() {Fighter warrior(1000);cout << "初始生命值:" << warrior.GetLife() << endl;warrior.UseDHD();cout << "当前生命值:" << warrior.GetLife() << endl;warrior.UseBXD();cout << "当前生命值:" << warrior.GetLife() << endl;warrior.UseSHD();cout << "当前生命值:" << warrior.GetLife() << endl;return 0;
}
第二步:提取共性并实现策略接口

在该实现中,Fighter 类包含所有道具使用的逻辑。可以提取出道具使用的共性,定义一个道具策略接口。

class ItemStrategy {
public:virtual void UseItem(Fighter* fighter) = 0;virtual ~ItemStrategy() {}
};
第三步:实现具体策略类

为每种道具创建具体的策略类,实现 ItemStrategy 接口。

  • 补血丹策略类
class ItemStrategy_BXD : public ItemStrategy {
public:void UseItem(Fighter* mainobj) override {mainobj->SetLife(mainobj->GetLife() + 200); // 补充200点生命值}
};
  • 大还丹策略类
class ItemStrategy_DHD : public ItemStrategy {
public:void UseItem(Fighter* mainobj) override {mainobj->SetLife(mainobj->GetLife() + 300); // 补充300点生命值}
};
  • 守护丹策略类
class ItemStrategy_SHD : public ItemStrategy {
public:void UseItem(Fighter* mainobj) override {mainobj->SetLife(mainobj->GetLife() + 500); // 补充500点生命值}
};
第四步:实现上下文类:

Fighter 类中添加设置道具策略的方法,并移除具体的道具使用逻辑,并定义战斗者的子类(可以不需要字类)。

class Fighter {
public:Fighter(int life) : m_life(life), itemStrategy(nullptr) {}void SetItemStrategy(ItemStrategy* strategy) {itemStrategy = strategy;}void UseItem() {if (itemStrategy) {itemStrategy->UseItem(this);}}int GetLife() {return m_life;}void SetLife(int life) {m_life = life;}private:int m_life;ItemStrategy* itemStrategy;
};
class F_Warrior : public Fighter {
public:F_Warrior(int life, int magic, int attack) : Fighter(life, magic, attack) {}// 其他战士特有的方法
};class F_Mage : public Fighter {
public:F_Mage(int life, int magic, int attack) : Fighter(life, magic, attack) {}// 其他法师特有的方法
};
第五步:更新主函数

更新主函数以使用新的策略模式结构。

int main() {Fighter warrior(1000);cout << "初始生命值:" << warrior.GetLife() << endl;ItemStrategy* strategy1 = new ItemStrategy_DHD();warrior.SetItemStrategy(strategy1);warrior.UseItem();cout << "当前生命值:" << warrior.GetLife() << endl;ItemStrategy* strategy2 = new ItemStrategy_BXD();warrior.SetItemStrategy(strategy2);warrior.UseItem();cout << "当前生命值:" << warrior.GetLife() << endl;ItemStrategy* strategy3 = new ItemStrategy_SHD();warrior.SetItemStrategy(strategy3);warrior.UseItem();cout << "当前生命值:" << warrior.GetLife() << endl;delete strategy1;delete strategy2;delete strategy3;return 0;
}

策略模式 UML 图

策略模式 UML 图2

策略模式的 UML 图解析
  • Context(环境类):也叫上下文类,是使用算法的角色,该类中维持着一个对抽象策略类的指针或引用。这里指Fighter类。
  • Stategy(抽象策略类):定义所支持的算法的公共接口,是所有策略类的父类。这里指 ItemStrategy 类。
  • ConcreteStrategy(具体策略类):抽象策略类的子类,实现抽象策略类中声明的接口。这里指ItemStrategy_BXDItemStrategy_DHDItemStrategy_SHD类。

策略模式优缺点

优点

  • 灵活性:可以在运行时选择不同的策略,增加了程序的灵活性和可扩展性。

  • 开放-关闭原则:新的策略可以通过实现策略接口而无需修改现有代码,符合开放-关闭原则。

  • 清晰的职责分离:将不同的算法封装在不同的类中,使得代码更加清晰,易于维护。

  • 减少条件语句:避免了使用大量的条件语句(如 if-elseswitch),使代码结构更加简洁。

  • 易于测试:每个策略类可以独立测试,便于单元测试和调试。

缺点

  • 类的数量增加:每种策略都需要一个新的类,可能导致类的数量增加,增加了系统的复杂性。

  • 客户端必须了解所有策略:客户端需要了解所有可用的策略,以便选择合适的策略,这可能增加了使用的复杂性。

  • 性能开销:在某些情况下,频繁地创建和销毁策略对象可能导致性能开销。

  • 不适合简单的算法:对于简单的算法,使用策略模式可能显得过于复杂,增加了不必要的抽象。

策略模式适用场景

  • 多种算法:当有多个算法可以选择时,策略模式可以将它们封装起来,方便切换。
  • 避免条件语句:当使用大量条件语句来选择算法时,可以使用策略模式来简化代码结构。
  • 动态选择算法:当需要在运行时选择算法时,策略模式提供了灵活性。
  • 算法复用:当多个类需要使用同一算法时,可以将算法封装成策略类,促进代码复用。

例一的完整代码

以下是完整的实现代码:

#include <iostream>
#include <vector>// 策略接口
class SortStrategy
{
public:virtual void sort(std::vector<int>& arr) = 0; // 策略接口
};// 具体策略:冒泡排序
class BubbleSort : public SortStrategy {
public:void sort(std::vector<int>& arr) override {for (size_t i = 0; i < arr.size() - 1; ++i) {for (size_t j = 0; j < arr.size() - i - 1; ++j) {if (arr[j] > arr[j + 1]) {std::swap(arr[j], arr[j + 1]);}}}}
};// 具体策略:快速排序
class QuickSort : public SortStrategy {
public:void sort(std::vector<int>& arr) override {quickSort(arr, 0, arr.size() - 1);}private:void quickSort(std::vector<int>& arr, int low, int high) {if (low < high) {int pivot = arr[high];int i = low - 1;for (int j = low; j < high; ++j) {if (arr[j] < pivot) {++i;std::swap(arr[i], arr[j]);}}std::swap(arr[i + 1], arr[high]);quickSort(arr, low, i);quickSort(arr, i + 2, high);}}
};// 上下文类
class Sorter {
private:SortStrategy* strategy;public:Sorter(SortStrategy* strategy) : strategy(strategy) {}void setStrategy(SortStrategy* strategy) {this->strategy = strategy;}void sort(std::vector<int>& arr) {strategy->sort(arr);}
};// 示例用法
int main() {std::vector<int> data = {5, 3, 8, 6, 2};Sorter sorter(new BubbleSort());sorter.sort(data); // 使用冒泡排序sorter.setStrategy(new QuickSort());sorter.sort(data); // 使用快速排序return 0;
}

例二的完整代码

#include <iostream>
using namespace std;class Fighter; // 类前向声明//道具策略类的父类
class ItemStrategy
{
public:virtual void UseItem(Fighter* mainobj) = 0;virtual ~ItemStrategy() {}
};//战斗者父类
class Fighter
{
public:Fighter(int life, int magic, int attack) :m_life(life), m_magic(magic), m_attack(attack) {}virtual ~Fighter() {}public:void SetItemStrategy(ItemStrategy* strategy) //设置道具使用的策略{itemstrategy = strategy;}void UseItem() //使用道具(吃药){itemstrategy->UseItem(this);}int  GetLife() //获取人物生命值{return m_life;}void SetLife(int life) //设置人物生命值{m_life = life;}private:ItemStrategy* itemstrategy = nullptr; //C++11中支持这样初始化protected:int m_life;int m_magic;int m_attack;
};//“战士”类,父类为Fighter
class F_Warrior :public Fighter
{
public:F_Warrior(int life, int magic, int attack) :Fighter(life, magic, attack) {}
};//“法师”类,父类为Fighter
class F_Mage :public Fighter
{
public:F_Mage(int life, int magic, int attack) :Fighter(life, magic, attack) {}
};//补血丹策略类
class ItemStrategy_BXD : public ItemStrategy
{
public:virtual void UseItem(Fighter* mainobj){mainobj->SetLife(mainobj->GetLife() + 200); //补充200点生命值cout << "使用补血丹,生命值增加200。" << endl;}
};//大还丹策略类
class ItemStrategy_DHD : public ItemStrategy
{
public:virtual void UseItem(Fighter* mainobj){mainobj->SetLife(mainobj->GetLife() + 300); //补充300点生命值cout << "使用大还丹,生命值增加300。" << endl;}
};//守护丹策略类
class ItemStrategy_SHD : public ItemStrategy
{
public:virtual void UseItem(Fighter* mainobj){mainobj->SetLife(mainobj->GetLife() + 500); //补充500点生命值cout << "使用守护丹,生命值增加500。" << endl;}
};int main()
{// 创建战斗者对象Fighter* prole_war = new Fighter(1000, 0, 200);// 打印初始生命值cout << "初始生命值:" << prole_war->GetLife() << endl;// 使用大还丹ItemStrategy* strategy1 = new ItemStrategy_DHD();prole_war->SetItemStrategy(strategy1);prole_war->UseItem();cout << "当前生命值:" << prole_war->GetLife() << endl;// 使用补血丹ItemStrategy* strategy2 = new ItemStrategy_BXD();prole_war->SetItemStrategy(strategy2);prole_war->UseItem();cout << "当前生命值:" << prole_war->GetLife() << endl;// 使用守护丹ItemStrategy* strategy3 = new ItemStrategy_SHD();prole_war->SetItemStrategy(strategy3);prole_war->UseItem();cout << "当前生命值:" << prole_war->GetLife() << endl;// 释放资源delete strategy1;delete strategy2;delete strategy3;delete prole_war;F_Mage mage(800, 300, 100);cout << "法师初始生命值:" << mage.GetLife() << endl;// 可以为法师设置道具策略并使用// ...return 0;
}

相关文章:

C++ 设计模式——策略模式

策略模式 策略模式主要组成部分例一&#xff1a;逐步重构并引入策略模式第一步&#xff1a;初始实现第二步&#xff1a;提取共性并实现策略接口第三步&#xff1a;实现具体策略类第四步&#xff1a;实现上下文类策略模式 UML 图策略模式的 UML 图解析 例二&#xff1a;逐步重构…...

【书生大模型实战营(暑假场)闯关材料】基础岛:第3关 浦语提示词工程实践

1.配置环境时遇到的问题 注意要使用terminal&#xff0c;而不是jupyter。 否则退出TMUX会话时&#xff0c;会出问题。 退出TMUX会话命令如下&#xff1a; ctrlB D # 先按CTRLB 随后按D另外一个是&#xff0c;端口转发命令 ssh -p XXXX rootssh.intern-ai.org.cn -CNg -L …...

C++ | Leetcode C++题解之第350题两个数组的交集II

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {sort(nums1.begin(), nums1.end());sort(nums2.begin(), nums2.end());int length1 nums1.size(), length2 nums2…...

遗传算法原理与实战(python、matlab)

遗传算法 1.什么是遗传算法 遗传算法&#xff08;Genetic Algorithm&#xff0c;简称GA&#xff09;是一种基于生物进化论和遗传学原理的全局优化搜索算法。它通过模拟自然界中生物种群的遗传机制和进化过程来解决复杂问题&#xff0c;如函数优化、组合优化、机器学习等。遗传…...

《黑神话:悟空》媒体评分解禁 M站均分82

《黑神话&#xff1a;悟空》媒体评分现已解禁&#xff0c;截止发稿时&#xff0c;M站共有43家媒体评测&#xff0c;均分为82分。 部分媒体评测&#xff1a; God is a Geek 100&#xff1a; 毫无疑问&#xff0c;《黑神话&#xff1a;悟空》是今年最好的动作游戏之一&#xff…...

安卓中携程和线程的区别。携程是指什么?

在安卓和其他编程环境中&#xff0c;协程&#xff08;Coroutine&#xff09;和线程&#xff08;Thread&#xff09;是两种不同的并发处理机制。它们各自有独特的特点和适用场景&#xff1a; 线程&#xff08;Thread&#xff09;&#xff1a; 线程是操作系统能够进行运算调度的最…...

部署flannel网络(master服务器执行)遇到错误

出现错误 “The connection to the server 192.168.0.23:6443 was refused - did you specify the right host or port?” 的原因通常是因为 Kubernetes API 服务器未能启动或无法访问。以下是一些可能的原因和解决方案&#xff1a; 解决方案 确认 Kubernetes API 服务器的状…...

超越IP-Adapter!阿里提出UniPortrait,可通过文本定制生成高保真的单人或多人图像。

阿里提出UniPortrait&#xff0c;能根据用户提供的文本描述&#xff0c;快速生成既忠实于原图又能灵活调整的个性化人像&#xff0c;用户甚至可以通过简单的句子来描述多个不同的人物&#xff0c;而不需要一一指定每个人的位置。这种设计大大简化了用户的操作&#xff0c;提升了…...

使用托管竞价实例在Amazon SageMaker上运行机器学习训练

这是本系列文章的第二篇&#xff0c;旨在通过动手实践&#xff0c;帮助大家学习亚马逊云科技的生成式AI相关技能。通过这些文章&#xff0c;大家将掌握如何利用亚马逊云科技的各类服务来应用AI技术。 那么让我们开始今天的内容吧&#xff01; 介绍 什么是Amazon SageMaker …...

AIoT智能物联网平台定义

随着科技的飞速发展&#xff0c;我们正步入一个由智能设备和互联网络构成的新时代。AIoT&#xff0c;即人工智能物联网&#xff08;Artificial Intelligence of Things&#xff09;&#xff0c;是这个时代的标志性产物。本文旨在探讨AIoT智能物联网平台的定义、核心组件、应用场…...

微服务设计原则——高性能:存储设计

文章目录 1.读写分离2.分库分表3.动静分离4.冷热分离5.重写轻读6.数据异构参考文献 任何一个系统&#xff0c;从单机到分布式&#xff0c;从前端到后台&#xff0c;功能和逻辑各不相同&#xff0c;但干的只有两件事&#xff1a;读和写。而每个系统的业务特性可能都不一样&#…...

hbase-manager图形化界面的安装与配置

相关资料下载 夸克网盘分享 1、上传项目到linux上 解压&#xff1a; 切换到conf目录下&#xff1a;/opt/installs/hbase-manager-2.0.8-hbase-2.x/conf/ 2、修改数据库配置信息 application-druid.yml 3、创建hbase-manager数据库(注意字符集编码)&#xff0c;导入数据库脚本…...

STM32之继电器与震动传感器的使用,实现震动灯

在STM32的外设应用中&#xff0c;继电器扮演着重要的角色。继电器作为一种电控制器件&#xff0c;其主要作用是通过小电流控制大电流的通断&#xff0c;实现电路的自动控制和保护。具体来说&#xff0c;继电器在STM32外设中的作用可以归纳为以下几点&#xff1a; 电路隔离与保…...

RS232(旧协议)与RS485(新协议)

RS232: RS485: RS485和RS232是两种常见的串行通信标准&#xff0c;它们在通信距离、速度、拓扑结构等方面存在显著差异。以下是它们的主要区别&#xff1a; 1. 物理层接口 RS232: 使用单端信号传输&#xff0c;即信号通过一根信号线和一根公共地线&#xff08;GND&#xff09…...

android13顶部状态栏里面调节背光,不隐藏状态栏面板

总纲 android13 rom 开发总纲说明 目录 1.前言 2.代码分析 3.修改方法 4.编译运行 5.彩蛋 1.前言 android13顶部状态栏里面调节背光,这个时候状态栏面板会被隐藏掉,有些需求就需要不隐藏这个面板。 2.代码分析 查找亮度条属性 id/brightness_slider ./frameworks/b…...

Webrtc之SDP协议

SDP简介 SDP 最常用于 RTC 实时通话的协商过程&#xff0c;在 WebRTC 中&#xff0c;通信双方在连接阶段使用 SDP 来协商后续传输过程中使用的音视频编解码器(codec)、主机候选地址、网络传输协议等。 在实际的应用过程中&#xff0c;通信双方可以使用 HTTP、WebSocket、Data…...

mfc140u.dll丢失错误解决方法的基本思路——四种修复mfc140u.dll的方法

当遇到mfc140u.dll丢失的错误时&#xff0c;意味着你的系统中缺失了一个重要的动态链接库文件&#xff0c;该文件是微软 Visual C Redistributable for Visual Studio 2015 的一部分&#xff0c;对于运行那些用 Visual C 开发的程序是必需的。今天就教你mfc140u.dll丢失错误解决…...

Python Django 后端架构开发: 中间件架构设计

&#x1f31f; Python Django 后端架构开发&#xff1a; 中间件架构设计 &#x1f539; 中间件项目测试&#xff1a;自定义中间件的 process_response 与 process_view 方法 在 Django 中&#xff0c;中间件是一种用于处理请求和响应的钩子&#xff0c;可以在视图处理前后对请…...

HTTP的认证方式

0.HTTP认证相关的一些基本概念 0.1 HTTP保护空间(HTTP Protection Space) 也称为认证领域(Authentication Realm),是指在HTTP认证中用来定义一组受保护资源的范围。保护空间通常由一个realm标识符来表示,它定义了用户需要提供凭据(如用户名和密码)才能访问的资源集合…...

10分钟学会LVM逻辑卷

华子目录 前言认识LVMLVM基本概念LVM整体流程LVM管理命令pvs&#xff0c;vgs&#xff0c;lvs命令pvs基本用法选项示例 vgs基本用法选项示例 lvs基本用法 pvcreate&#xff0c;vgcreate&#xff0c;lvcreate命令pvcreate示例 vgcreate基本用法示例选项 lvcreate基本用法示例 pvr…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

C++.OpenGL (14/64)多光源(Multiple Lights)

多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机&#xff0c;因为在使用过程中发现 Airsim 对外部监控相机的描述模糊&#xff0c;而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置&#xff0c;最后在源码示例中找到了&#xff0c;所以感…...

宇树科技,改名了!

提到国内具身智能和机器人领域的代表企业&#xff0c;那宇树科技&#xff08;Unitree&#xff09;必须名列其榜。 最近&#xff0c;宇树科技的一项新变动消息在业界引发了不少关注和讨论&#xff0c;即&#xff1a; 宇树向其合作伙伴发布了一封公司名称变更函称&#xff0c;因…...