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

设计模式实践:模板方法、观察者与策略模式详解

目录

  • 1 模板方法
    • 1.1 模板方法基本概念
    • 1.2 实验
      • 1.2.1 未使用模板方法实现代码
      • 1.2.2 使用模板方法的代码
  • 2 观察者模式
    • 2.1 观察者模式基本概念
    • 2.2 实验
  • 3 策略模式
    • 3.1 策略模式基本概念
    • 3.2 实验

1 模板方法

1.1 模板方法基本概念

  • 定义:一个操作中的算法的骨架 ,而将一些步骤延迟到子类中。 Template Method使得子类可以不
    改变一个算法的结构即可重定义该算法的某些特定步骤。
  • 要点:
    • 最常用的设计模式,子类可以复写父类子流程,使父类的骨架流程丰富
    • 父类 protected 保护子类需要复写的子流程;这样子类的子流程只能父类来调用

1.2 实验

背景
某个品牌动物园,有一套固定的表演流程,但是其中有若干个表演子流程可创新替换,以尝试迭代更新表演流程;

1.2.1 未使用模板方法实现代码

#include <iostream>
using namespace std;#if 0
class ZooShow {
public:void Show0() {cout << "show0" << endl;}void Show2() {cout << "show2" << endl;}
};class ZooShowEx {
public:void Show1() {cout << "show1" << endl;}void Show3() {cout << "show3" << endl;}
};// 不满足单一职责 , 开 扩展 修改闭原则
// 动物园固定流程,迭代创新
// 稳定和变化   一定的方向上变化
#else if 2
class ZooShow {
public:ZooShow(int type = 1) : _type(type) {}public:void Show() {if (Show0())PlayGame(); // 里氏替换Show1();Show2();Show3();}// 接口隔离 不要让用户去选择它们不需要的接口
private:void PlayGame() {cout << "after Show0, then play game" << endl;}private:bool Show0() {cout << _type << " show0" << endl;return true;}void Show1() {if (_type == 1) {cout << _type << " Show1" << endl;} else if (_type == 2) {cout << _type << " Show1" << endl;} else if (_type == 3) {}}void Show2() {if (_type == 20) {}cout << "base Show2" << endl;}void Show3() {if (_type == 1) {cout << _type << " Show1" << endl;} else if (_type == 2) {cout << _type << " Show1" << endl;}}
private:int _type;
};#endifint main () {
#if 0ZooShow *zs = new ZooShow;ZooShowEx *zs1 = new ZooShowEx;zs->Show0();zs1->Show1();zs->Show2();zs1->Show3();
#else if 2ZooShow *zs = new ZooShow(1);zs->Show();
#endifreturn 0;
}

分析:

  • 1.缺乏可扩展性
    在当前代码里,ZooShow 类的 Show 方法内包含了很多 if - else 条件判断,用来依据不同的 _type 值执行不同的逻辑。要是需要新增一种表演类型,就得修改 Show 方法,添加新的 if - else 分支。这违背了开闭原则(对扩展开放,对修改关闭),代码的可扩展性较差。例如,如果要增加 _type == 4 的表演流程,就得在各个方法里添加对应的判断逻辑。
  • 2.代码复用性低
    每个表演类型的逻辑都被硬编码在 ZooShow 类的各个方法中,不同表演类型之间的公共逻辑没有得到很好的复用。如果某些表演类型有相似的流程,当前代码无法有效复用这些公共部分,会造成代码冗余。
  • 3.违反单一职责原则
    ZooShow 类承担了过多的职责,它不仅定义了表演的流程,还包含了每种表演类型的具体逻辑**。当表演类型增多或者表演流程发生变化时,这个类会变得越来越复杂,难以维护**。
  • 4.可读性和可维护性差
    大量的 if - else 条件判断使得代码的逻辑变得复杂,降低了代码的可读性。而且,当需要修改或添加新的表演类型时,需要在多个方法中查找和修改相关逻辑,增加了维护的难度。

1.2.2 使用模板方法的代码

学习设计模式 我们可以通过这些 要点

  • 定义:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method 使得子类可以不改变一个算法的结构即可重定义该算法。
  • 解决的问题
    确定点:算法骨架
    变化点:子流程需要变化
  • 代码结构
    基类中存骨架流程接口
    所有子流程对子类开放并且是虚函数
    多态使用方式
  • 符合哪些设计原则
    单一职责
    开闭
    依赖倒置:子类扩展时,需要依赖基类的虚函数实现;使用者只依赖接口
    封装变化点:protected
    接口隔离
    最小知道原则
  • 如何扩展
    实现子类继承基类,重写子流程
    通过多态调用方式使用
#include <iostream>
using namespace std;// 抽象基类,定义表演流程的模板
class ZooShowTemplate {
public:// 模板方法,定义表演的整体流程void Show() {if (Show0())PlayGame();Show1();Show2();Show3();}virtual ~ZooShowTemplate() {}protected:// 具体步骤的虚函数,可在子类中重写virtual bool Show0() {cout << "show0" << endl;return true;}virtual void PlayGame() {cout << "after Show0, then play game" << endl;}virtual void Show1() = 0;virtual void Show2() = 0;virtual void Show3() = 0;
};// 具体表演类型 1
class ZooShowType1 : public ZooShowTemplate {
protected:void Show1() override {cout << "1 Show1" << endl;}void Show2() override {cout << "base Show2" << endl;}void Show3() override {cout << "1 Show3" << endl;}
};// 具体表演类型 2
class ZooShowType2 : public ZooShowTemplate {
protected:void Show1() override {cout << "2 Show1" << endl;}void Show2() override {cout << "base Show2" << endl;}void Show3() override {cout << "2 Show3" << endl;}
};int main() {ZooShowTemplate* zs1 = new ZooShowType1();zs1->Show();ZooShowTemplate* zs2 = new ZooShowType2();zs2->Show();delete zs1;delete zs2;return 0;
}

解决的问题

  • 确定点(算法骨架):代码里 ZooShowTemplate 类的 Show 方法确定了表演流程这个算法骨架,固定了表演的整体执行顺序。
  • 变化点(子流程需要变化):不同类型的表演,如 ZooShowType1 和 ZooShowType2,它们的 Show1、Show2、Show3 具体实现是不同的,这就是子流程的变化点,通过继承基类并重写相应虚函数来实现不同的子流程

代码结构

  • 基类中存骨架流程接口:ZooShowTemplate 类中定义的 Show 方法就是骨架流程接口,它包含了整个表演流程的逻辑。
  • 所有子流程对子类开放并且是虚函数:Show0、PlayGame、Show1、Show2、Show3 这些子流程方法在 ZooShowTemplate 类中都被定义为虚函数,方便子类重写,实现不同的子流程逻辑。
  • 多态使用方式:在 main 函数中,通过基类指针 ZooShowTemplate* 分别指向 ZooShowType1 和 ZooShowType2 的对象,然后调用 Show 方法,运行时根据实际指向的子类对象调用相应子类重写的方法,体现了多态性。

符合的设计原则

  • 单一职责:ZooShowTemplate 类负责定义表演流程骨架,各个子类负责具体表演类型的子流程实现,职责划分清晰 ,每个类只专注于自己的职责。
  • 开闭:当需要新增一种表演类型时,如 ZooShowType3,只需创建一个新类继承 ZooShowTemplate 并重写相关虚函数,不需要修改 ZooShowTemplate 类的代码,对扩展开放,对修改关闭。
  • 依赖倒置:子类扩展时依赖基类的虚函数实现,比如 ZooShowType1 和 ZooShowType2 依赖 ZooShowTemplate 中定义的虚函数;使用者(main 函数)只依赖 ZooShowTemplate 这个抽象基类接口,而不是具体子类,降低了耦合度。
  • 封装变化点:在 ZooShowTemplate 类中,将一些可能变化的子流程方法(如 Show1、Show2 等)定义为虚函数,并且访问修饰符为 protected,对外部隐藏了具体实现细节,同时方便子类重写来实现变化。
  • 接口隔离:虽然代码中未明显体现接口隔离的典型场景,但从某种程度上,每个子类只实现自己需要的虚函数,没有被迫依赖不需要的接口方法。
  • 最小知道原则:子类只需要了解与自己相关的基类虚函数,不需要了解基类中其他不必要的实现细节,减少了类之间的信息交互。

如何扩展

  • 实现子类继承基类,重写子流程:如代码中 ZooShowType1 和 ZooShowType2 继承自 ZooShowTemplate,并重写了 Show1、Show2、Show3 等子流程方法,实现不同表演类型的定制。
  • 通过多态调用方式使用:在 main 函数中,通过基类指针调用 Show 方法,利用多态性根据实际子类对象调用相应的重写方法,实现不同表演类型的流程执行。

2 观察者模式

2.1 观察者模式基本概念

  • 定义:对象间的一种一对多(变化)的依赖关系,以便当一个对象(Subject)的状态发生改变时,所有依赖于它的对象都得到通知并自动更新
  • 特性
    • 松耦合:主题和观察者相互独立,主题无需知道观察者具体细节,只知其实现了观察者接口 。比如电商系统中商品信息(主题)变化,不同的展示模块(观察者)可独立更新,互不干扰。
    • 动态性:观察者可随时添加或移除,不影响系统其他部分 。例如新闻推送系统,新用户(观察者)可随时订阅(添加)或退订(移除)频道(主题)。

2.2 实验

背景:
气象站发布气象资料给数据中心,数据中心经过处理,将气象信息更新到两个不同的显示终端(A和B)
实现伪代码

#include <vector>//
class IDisplay {
public:virtual void Show(float temperature) = 0;virtual ~IDisplay() {}
};class DisplayA : public IDisplay {
public:virtual void Show(float temperature);
private:void jianyi();
};class DisplayB : public IDisplay{
public:virtual void Show(float temperature);
};class DisplayC : public IDisplay{
public:virtual void Show(float temperature);
};class WeatherData {
};class DataCenter {
public:void Attach(IDisplay * ob);void Detach(IDisplay * ob);void Notify() {float temper = CalcTemperature();for (auto iter = obs.begin(); iter != obs.end(); iter++) {(*iter)->Show(temper);}}// 接口隔离
private:virtual WeatherData * GetWeatherData();virtual float CalcTemperature() {WeatherData * data = GetWeatherData();// ...float temper/* = */;return temper;}std::vector<IDisplay*> obs;
};int main() {DataCenter *center = new DataCenter;IDisplay *da = new DisplayA();IDisplay *db = new DisplayB();IDisplay *dc = new DisplayC();center->Attach(da);center->Attach(db);center->Attach(dc);center->Notify();//-----center->Detach(db);center->Notify();return 0;
}

定义与解决的问题

  • 定义体现:观察者模式定义对象间一对多依赖关系,代码中 DataCenter 类相当于主题(被观察者),IDisplay 及其派生类**(DisplayA、DisplayB、DisplayC )相当于观察者** 。DataCenter 维护着多个 IDisplay 指针(观察者),当温度数据计算出来(主题状态变化)时,通知所有注册的观察者,符合一对多依赖关系的定义。
  • 稳定点与变化点
    • 稳定点:“一” 对应的是 DataCenter 类,它是主题,在系统中相对稳定,负责管理观察者和通知逻辑。
    • 变化点:“多” 对应的是 IDisplay 的不同派生类实例,如 DisplayA、DisplayB、DisplayC ,可以随时增加新的显示类(“多” 增加 ),或者移除已有的显示类(“多” 减少 ),比如在 main 函数中通过 Attach 和 Detach 方法进行添加和移除操作。

代码结构
-代码定义了主题类 DataCenter ,通过 std::vector<IDisplay*> 来存储观察者。观察者通过抽象接口 IDisplay 定义,具体观察者类 DisplayA、DisplayB、DisplayC 实现该接口。DataCenter 有 Attach、Detach 方法管理观察者,Notify 方法用于通知观察者。结构上满足观察者模式中主题与观察者的基本组织形式。
符合的设计原则

  • 面向接口编程:代码中定义了抽象接口 IDisplay ,DataCenter 类依赖 IDisplay 接口来管理观察者,而不是具体的观察者类(如 DisplayA、DisplayB 等 )。例如 DataCenter 的 Attach 方法接收 IDisplay * 类型参数,体现了面向接口编程,降低了耦合度。
  • 接口隔离:IDisplay 接口只定义了 Show 方法,每个具体的显示类只需要实现这个与自身显示功能相关的方法,没有被迫实现不必要的接口方法。并且 DataCenter 类内部也有一些方法(如 GetWeatherData 等 )相对隔离,符合接口隔离原则。
  • 封装变化点
    attach:在代码中对应 Attach 方法,用于将观察者(IDisplay 的派生类实例 )添加到 DataCenter 的观察者列表中,封装了增加观察者这个变化点。
    detach:对应 Detach 方法,用于从观察者列表中移除观察者,封装了减少观察者这个变化点。

如何扩展

若要扩展系统,比如增加新的显示方式(新的观察者 ),可以创建一个新的类继承自 IDisplay ,实现 Show 方法,然后在 main 函数中通过 DataCenter 的 Attach 方法将其添加到观察者列表中,就能参与到温度数据的显示通知流程中。

3 策略模式

3.1 策略模式基本概念

定义与核心思想

  • 定义一系列算法:把相关算法进行归纳整理,形成一个算法集合。比如电商系统中计算商品折扣,有固定折扣、满减折扣、会员专属折扣等不同算法 。
  • 封装每个算法:将每个算法独立封装在对应的策略类中。以支付场景为例,支付宝支付、微信支付、银行卡支付等,每种支付方式的实现细节都封装在各自的策略类里,外部无需了解具体支付流程(如网络请求、加密处理等 )。
  • 算法可相互替换:在运行时,可根据实际情况灵活切换不同策略,而不影响使用算法的客户端。例如地图导航,用户可在 “最短距离”“最快速度”“避开拥堵” 等不同路径规划策略间切换 。
    组成部分
  • 策略接口(抽象策略角色):定义算法的公共接口,规定算法应具备的方法签名。比如定义一个计算税费的策略接口,其中包含计算税费的抽象方法 calculateTax() 。
  • 具体策略类:实现策略接口,提供具体算法的实现。如上述计算税费的场景,有针对不同地区税率计算税费的具体策略类,像 “北京地区税费计算类”“上海地区税费计算类” 等,分别实现 calculateTax() 方法。
  • 上下文类:持有策略接口的引用,负责在合适时机调用策略对象的算法。例如电商系统中结算模块作为上下文类,它持有税费计算策略接口的引用,在结算时调用具体策略类(如根据收货地区选择对应地区的税费计算策略 )来计算税费。

3.2 实验

背景:某商场节假日有固定促销活动,为了加大促销力度,现提升国庆节促销活动规格
实现

class Context {};class ProStategy {
public:virtual double CalcPro(const Context &ctx) = 0;virtual ~ProStategy(); 
};
// cpp
class VAC_Spring : public ProStategy {
public:virtual double CalcPro(const Context &ctx){}
};
// cpp
class VAC_QiXi : public ProStategy {
public:virtual double CalcPro(const Context &ctx){}
};
class VAC_QiXi1  : public VAC_QiXi {
public:virtual double CalcPro(const Context &ctx){}
};
// cpp
class VAC_Wuyi : public ProStategy {
public:virtual double CalcPro(const Context &ctx){}
};
// cpp
class VAC_GuoQing : public ProStategy {
public:virtual double CalcPro(const Context &ctx){}
};class VAC_Shengdan : public ProStategy {
public:virtual double CalcPro(const Context &ctx){}
};class Promotion {
public:Promotion(ProStategy *sss) : s(sss){}~Promotion(){}double CalcPromotion(const Context &ctx){return s->CalcPro(ctx);}
private:ProStategy *s;
};int main () {Context ctx;ProStategy *s = new VAC_QiXi1();Promotion *p = new Promotion(s);p->CalcPromotion(ctx);return 0;
}

解决的问题

  • 稳定点:在该商场促销场景中,“客户端与算法的调用关系” 是稳定点。从代码看,Promotion 类(客户端)通过构造函数接收 ProStategy 指针(算法相关),并在 CalcPromotion 方法中固定地调用 s->CalcPro(ctx) 来执行促销算法,这种调用关系相对稳定。
  • 变化点
    • 新加算法:当商场要增加新的促销活动时,比如后续可能新增某个节日的促销策略,就需要添加新的具体策略类。像代码中如果要新增 “元旦促销策略”,可以创建新类继承自 ProStategy 并实现 CalcPro 方法。
    • 算法内容改变:已有的促销策略(如 VAC_QiXi 等类 ),其内部的促销计算逻辑(CalcPro 方法的实现 )可能会根据商场需求进行调整和改变。
      代码结构
      定义了抽象策略类 ProStategy ,其中声明了纯虚函数 CalcPro ,用于定义促销算法的接口。一系列具体策略类(VAC_Spring、VAC_QiXi 等 )继承自 ProStategy ,并实现 CalcPro 方法,各自代表不同节日的促销算法。Context 类目前为空,但在策略模式中通常用于存储上下文相关信息,供策略类使用。
      Promotion 类作为上下文类,持有 ProStategy 指针,通过构造函数进行依赖注入(接收具体的策略对象 ),并在 CalcPromotion 方法中调用策略对象的 CalcPro 方法来执行促销计算。

设计原则

  • 接口隔离
    • 依赖注入:Promotion 类通过构造函数 Promotion(ProStategy *sss) 将具体的促销策略对象注入进来,实现了类与具体策略的解耦。比如在 main 函数中可以灵活地将不同的 ProStategy 子类对象(VAC_QiXi1 等 )注入到 Promotion 中。
    • 解决通过一个接口解决两个类的依赖:ProStategy 接口将 Promotion 类和具体的促销策略类(如 VAC_QiXi 等 )解耦,使得 Promotion 类只依赖于抽象接口,而不依赖具体策略类的实现细节,解决了它们之间的依赖问题。
  • 面向接口编程:整个代码围绕 ProStategy 接口展开,Promotion 类依赖 ProStategy 接口,而不是具体的策略类。在 main 函数中也是通过 ProStategy 指针来操作具体的策略对象,体现了面向接口编程,降低了代码间的耦合度。
  • 开闭原则:当需要新增促销策略(如新增节日促销 )时,只需创建新的类继承 ProStategy 并实现 CalcPro 方法,无需修改现有的 Promotion 类以及其他已有的策略类代码,对扩展开放,对修改关闭。
    其实还有一个组合优于继承的原则

如何扩展代码
若要扩展代码,比如增加新的促销策略,只需创建一个新的类继承自 ProStategy ,并实现 CalcPro 方法。然后在 main 函数中,创建该新策略类的对象,并将其注入到 Promotion 类中,即可使用新的促销策略。例如新增 “中秋促销策略”,可以编写一个新类继承 ProStategy ,实现 CalcPro 方法来定义中秋促销的计算逻辑,然后在 main 函数中按现有方式使用这个新策略。
怎么调用

 ProStategy *s = new VAC_QiXi1();Promotion *p = new Promotion(s);p->CalcPromotion(ctx);

多态调用

相关文章:

设计模式实践:模板方法、观察者与策略模式详解

目录 1 模板方法1.1 模板方法基本概念1.2 实验1.2.1 未使用模板方法实现代码1.2.2 使用模板方法的代码 2 观察者模式2.1 观察者模式基本概念2.2 实验 3 策略模式3.1 策略模式基本概念3.2 实验 1 模板方法 1.1 模板方法基本概念 定义&#xff1a;一个操作中的算法的骨架 &…...

Google的AI模型Gemini和Gemini网络协议

粉丝私信问我&#xff1a;gemini如何访问&#xff1f; "Gemini如何访问"需明确区分两种完全不同的技术体系&#xff1a;Google的AI模型Gemini和Gemini网络协议。以下是两者的访问方式详解&#xff1a; 一、访问Google的Gemini AI模型 1. 通过Web应用 地址&#xf…...

HTTP实现心跳模块

HTTP实现心跳模块 使用轻量级的cHTTP库cpp-httplib重现实现HTTP心跳模块 头文件HttplibHeartbeat.h #ifndef HTTPLIB_HEARTBEAT_H #define HTTPLIB_HEARTBEAT_H#include <string> #include <thread> #include <atomic> #include <chrono> #include …...

基于web的民宿信息系统(源码+lw+部署文档+讲解),源码可白嫖!

摘要 随着信息时代的来临&#xff0c;民宿过去的民宿信息方式的缺点逐渐暴露&#xff0c;对过去的民宿信息的缺点进行分析&#xff0c;采取计算机方式构建民宿信息系统。本文通过阅读相关文献&#xff0c;研究国内外相关技术&#xff0c;提出了一种民宿信息管理、民宿信息管理…...

使用OpenSceneGraph (osg)实现一个星系漫游

简介 使用OpenSceneGraph (osg)实现了一个太阳系漫游的程序&#xff0c;具有以下特点&#xff1a; 1.通过按键控制飞行器前进后退、空间姿态&#xff1b; 2.星系渲染&#xff1b; 3.背景星空渲染&#xff1b; 效果 提供了一张超大的星空背景图 代码示例 int main(int a…...

笔试专题(九)

文章目录 十字爆破&#xff08;暴力&#xff09;题解代码 比那名居的桃子&#xff08;滑动窗口/前缀和&#xff09;题解代码 分组&#xff08;暴力枚举 优化二分&#xff09;题解代码 十字爆破&#xff08;暴力&#xff09; 题目链接 题解 1. 暴力 预处理 2. 如果单纯的暴…...

sklearn决策树 待更新

注意&#xff1a;sklearn中所有的决策树模型包括回归决策树实现的是CART决策树算法&#xff0c;在官方文档中有介绍。sklearn中的决策树模型最终得到的树结构都是二叉树&#xff0c;因为CART算法生成的就是二叉树。 DecisionTreeClassifier类 如果待预测样本有多个类别具有相同…...

eino v0.3.21 重磅发布!节点中断控制+空值映射支持,AI应用开发再添神器!​

CloudWeGo/eino v0.3.21 作为最新补丁版本&#xff0c;聚焦流程控制与数据映射两大核心场景&#xff0c;为AI应用与微服务开发者提供更灵活的调试能力与容错设计&#xff01; 1. 节点中断控制&#xff08;Feat: Node Interrupt&#xff09; • 功能亮点&#xff1a;新增 node …...

力扣每日打卡 50. Pow(x, n) (中等)

[TOC](力扣 50. Pow(x, n) 中等) 前言 这是刷算法题的第十一天&#xff0c;用到的语言是JS 题目&#xff1a;力扣 50. Pow(x, n) (中等) 一、题目内容 实现 pow(x, n) &#xff0c;即计算 x 的整数 n 次幂函数&#xff08;即&#xff0c;xn &#xff09;。 示例 1&#xff1…...

Mac M1管理多个Node.js版本

目录 1. 使用 nvm (Node Version Manager) 1.1.安装 nvm 1.2.安装Node.js版本 1.3.查看已安装的node版本列表 1.4.使用特定版本的Node.js 1.5.查看当前使用的版本 2. 使用 fnm (Fast Node Manager) 2.1.安装 fnm 2.2.安装Node.js版本 2.3.查看已安装的版本 2.4.使用…...

arm_math.h、arm_const_structs.h 和 arm_common_tables.h

在 ​​FOC&#xff08;Field-Oriented Control&#xff0c;磁场定向控制&#xff09;​​ 中&#xff0c;arm_math.h、arm_const_structs.h 和 arm_common_tables.h 是 CMSIS-DSP 库的核心组件&#xff0c;用于实现高效的数学运算、预定义结构和查表操作。以下是它们在 FOC 控…...

每天五分钟深度学习:非线性激活函数的导数

本文重点 本文探讨了神经网络中几种常见非线性激活函数(Sigmoid、Tanh、ReLU、Leaky ReLU、ELU、Softmax)的导数特性。通过对各激活函数导数的数学推导与实际应用分析,揭示了不同激活函数在梯度传播、收敛速度及模型表达能力方面的差异。研究发现,ReLU及其变体在计算效率与…...

OpenHarmony5.0.2 USB摄像头适配

开发环境 OpenHarmony5.0.2 RK3568 USB摄像头 遇到问题 编译后插上USB摄像头后打开相机无图像 解决思路 5.0.2版本是支持USB摄像头的&#xff0c;需要修改默认的板载相机配置即可。 修改代码 1、修改配配置 文件地址&#xff1a;vendor/hihope/rk3568/hdf_config/uhdf…...

vue: router基础用法

router基础用法 1.安装router2.配置router3.路由编程1.编程式导航2.声明式导航 1.安装router 在node环境下&#xff0c;直接运行 npm install router42.配置router 创建文件夹并命名为router 在router文件夹中创建index.js index.js示例配置如下&#xff1a; import { creat…...

IDE中使用Spring Data Redis

步骤一&#xff1a;导入Spring Data Redis的maven坐标 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency> 步骤二&#xff1a;配置Redis数据源 步骤三&…...

【计网】网络交换技术之报文交换(复习自用,了解,重要3)

复习自用的&#xff0c;处理得比较草率&#xff0c;复习的同学或者想看基础的同学可以看看&#xff0c;大佬的话可以不用浪费时间在我的水文上了 另外两种交换技术可以直接点击链接访问相关笔记&#xff1a; 电路交换 分组交换 一、报文交换的定义 报文交换&#xff08;Me…...

GitLab 17.x 配置 https

文章目录 使用外部 nginx 参考&#xff1a;https://docs.gitlab.com/omnibus/settings/nginx.html 使用内置 nginx 参考&#xff1a;https://docs.gitlab.com/omnibus/settings/ssl/index.html#configure-https-manually // 使用自己手工申请证书 $ mkdir /etc/gitlab/ssl $ m…...

中间件--ClickHouse-1--基础介绍(列式存储,MPP架构,分布式计算,SQL支持,向量化执行,亿万级数据秒级查询)

1、概述 ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)。它由俄罗斯的互联网巨头Yandex为解决其内部数据分析需求而开发&#xff0c;并于2016年开源。专为大规模数据分析&#xff0c;实时数据分析和复杂查询设计&#xff0c;具有高性能、实时数据和可扩展性等…...

【编写Node接口;接口动态获取VUE文件并异步加载, 并渲染impoort插件使用】

编写Node接口&#xff1b;接口动态获取VUE文件并异步加载, 并渲染impoort插件使用&#xff1b; vue3-sfc-loader主要特征&#xff1a; 编写Node接口&#xff1a;Vue2项目使用&#xff1a;Vue3项目使用&#xff1a;&#xff08;页面按需加载插件、图片等&#xff09;主要使用&am…...

vue入门:template 和 JSX

temlplate 和 jsx 最终渲染时都是创建 dom 节点 template 和 JSX 混合使用 <template><div><span>Message: {{ msg }}</span><br/><VNodes :vnodes"getJSXSpan()"/><VNodes :vnodes"getAnchoredHeading(4)"/>…...

[Dify] Dify 本地部署及连接 Ollama 模型全流程指南

在构建私有化智能应用时,Dify 作为一款开源的大模型应用开发平台,具备强大的插件体系和可扩展能力。本文将详细介绍如何在本地环境中部署 Dify,并成功连接本地的 Ollama 模型,解决实际部署过程中常见的问题与错误。 一、本地部署 Dify 步骤详解 1. 安装 Docker 环境(以 W…...

基于PyQt5的Jupyter Notebook转Python工具

一、项目背景与核心价值 在数据科学领域,Jupyter Notebook因其交互特性广受欢迎,但在生产环境中通常需要将其转换为标准Python文件。本文介绍一款基于PyQt5开发的桌面级转换工具,具有以下核心价值: 可视化操作:提供友好的GUI界面,告别命令行操作 批量处理:支持目录递归…...

从自然语言到 JSON 数据交互:探索 MCP 协议的自动化任务实现

好的&#xff01;以下是基于我们讨论的关于 MCP 协议、JSON 数据交互以及自然语言到 JSON 转换的实现过程的总结&#xff0c;格式化为一篇 CSDN 风格的博客记录。这篇文章将记录你的发现&#xff0c;适合分享给技术社区。 从自然语言到 JSON 数据交互&#xff1a;探索 MCP 协议…...

n8n 本地部署及实践应用,实现零成本自动化运营 Telegram 频道(保证好使)

n8n 本地部署及实践应用&#xff0c;实现零成本自动化运营 Telegram 频道&#xff08;保证好使&#xff09; 简介 n8n 介绍 一、高度可定制性 二、丰富的连接器生态 三、自托管部署&#xff08;本地部署&#xff09; 四、社区驱动 n8n 的部署 一、前期准备 二、部署步…...

嵌入式学习(37)-STM32串口发送中断的实现

一、概述 项目中需要用到发送中断&#xff0c;所以了解了发送中断的一些知识。 二、应用 状态寄存器USART_SR的复位值为0x00C0H, 也就是第七位TXE和第六位TC复位值为1&#xff0c;而TXE1,表明发送数据寄存器为空&#xff0c; TC1表明发送已完成。 USART_ITConfig(USART1, USA…...

Android envsetup与Python venv使用指南

Android envsetup 和 Python venv 是两种完全不同的环境配置工具&#xff0c;分别服务于不同的开发场景。以下是对它们的详细解释及使用方法&#xff1a; 1. Android envsetup 用途&#xff1a; Android envsetup 是 Android 源码开发中的环境配置脚本&#xff08;envsetup.sh…...

安卓关机和重启源码流程

// systemui关机 frameworks/base/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java Overridepublic void shutdown() {try {mBarService.shutdown();} catch (RemoteException e) {}}frameworks/base/services/core/java/com/android…...

解决单设备号双目摄像头调用难题:经验分享与总结

解决单设备号双目摄像头调用难题:经验分享与总结 在计算机视觉项目中,双目摄像头的调用是常见需求,但过程中往往会遇到各种挑战。最近,我就经历了一段曲折但最终成功解决问题的历程,现在将这段宝贵经验分享给大家。 一、问题背景 我手头的双目摄像头仅有一个设备号(设…...

【RL系列】DAPO: An Open-Source LLM Reinforcement Learning System at Scale

1. 简介 尽管RL对complex reasoning效果提升有重要作用&#xff0c;但是在openAI o1和DeepSeek R1 technical report上都没有详细的实验细节。本文主要提出了DAPO算法&#xff0c;提出了4个关键技术点并开源参数和代码。在AIME 2024验证了DAPO算法的有效性。 2. Tricks Exc…...

五子棋(测试报告)

文章目录 一、项目介绍二、测试用例三、自动化测试用例的部分展示注册登录游戏大厅游戏匹配 总结 一、项目介绍 本项目是一款基于Spring、SpringMVC、MyBatis、WebSocket的双人实时对战五子棋游戏,游戏操作便捷&#xff0c;功能清晰明了。 二、测试用例 三、自动化测试用例的…...

【小工具】定时任务执行器

定时任务执行器 背景版本代码JobJob执行机 背景 有时我们的项目内需要一个定时执行器来执行某些任务&#xff0c;就需要一个简单好用的定时任务机。 注意&#xff0c;这个定时任务机并不原生支持分布式&#xff0c;如果需要分布式的功能请自己实现。 版本 jdk21 代码 Job …...

LVGL源码(7):渲染

在LVGL源码(4):LVGL关于EVENT事件的响应逻辑_lvgl实现显示打车-CSDN博客这篇文章中&#xff0c;我们提到了LVGL的三大步骤&#xff1a;检测用户输入操作、调用我们编写的逻辑、在屏幕上显示对应的画面&#xff1b;而在学习完“样式”之后&#xff0c;我们或许可以将上述步骤说明…...

02_通过调用硅基流动平台deepseekapi按输入的标题生成文章

from openai import OpenAIclient OpenAI(base_urlhttps://api.siliconflow.cn/v1,api_keyyou api-key )# 定义关键词变量 keyword "人性的弱点都有哪些&#xff1f;"# 发送带有流式输出的请求 response client.chat.completions.create(model"deepseek-ai/D…...

三、Virtual Device Manager

一、创建AVD AVD是Android Virtual Device&#xff08;安卓虚拟设备&#xff09;,我们可以启动Android Studio 选择 Virtual Device Manager 创建并启动一个模拟器。 二、设置屏幕大小 上面直接创建的镜像是不能设置屏幕大小的&#xff0c;启动后笔记本屏幕都放不下&#xff…...

MATLAB2022b安装

1 从百度网盘下载MATLAB2022b&#xff0c;下载完成后解压到某个文件夹&#xff1b; 链接: MATLAB2022b 提取码: 6666 2 打开解压后的文件夹&#xff0c;进入setup文件夹&#xff0c;双击打开“setup.exe”文件&#xff1b; 3 在弹出窗口中选择“高级选项”-->“我有文件安…...

计算机编码

计算机&#xff0c;不能直接存储文字&#xff0c;存储的是编码。 计算机只能处理二进制的数据&#xff0c;其它数据&#xff0c;比如&#xff1a;0-9、a-z、A-Z&#xff0c;这些字符&#xff0c;我们可以定义一套规则来表示。假如&#xff1a;A用110表示&#xff0c;B用111表示…...

Dell EMC Unity NAS 认证方式介绍

近日有个客户要配置EMC Unity的NAS访问&#xff0c;我们知道NAS有Linux环境下的NFS和Windows环境下的SMB&#xff08;也叫做CIFS&#xff09;。单独配置其中的一种访问协议相对简单&#xff0c;但是客户提出的要求是要对文件系统同时NFS和SMB访问&#xff0c;这就有些复杂&…...

SpringAi 会话记忆功能

在使用chatGPT&#xff0c;豆包等产品后&#xff0c;就会发现他们的会话有“记忆”功能。 那么我们用API接口的话&#xff0c;这个是怎么实现的呢&#xff1f; 属于比较粗暴的方式&#xff0c;把之前的内容与新的提示词一起再次发给大模型。让我们看到他们有记忆功能。 下面介绍…...

BUUCTF-web刷题篇(25)

34.the mystery of ip 给出链接&#xff0c;输入得到首页&#xff1a; 有三个按钮&#xff0c;flag点击后发现页面窃取客户端的IP地址&#xff0c;通过给出的github代码中的php文件发现可以通过XFF或Client-IP传入值。使用hackbar或BP 使用XSS&#xff0c;通过github给出的目录…...

Elasticsearch 性能优化:从原理到实践的全面指南

Elasticsearch&#xff08;ES&#xff09;作为一款基于 Lucene 的分布式搜索和分析引擎&#xff0c;广泛应用于日志分析、搜索引擎和实时数据处理等场景。然而&#xff0c;在高并发、大数据量环境下&#xff0c;Elasticsearch 的性能可能面临瓶颈&#xff0c;如查询延迟高、索引…...

UITableVIew性能优化概述

UITableVIew性能优化概述 文章目录 UITableVIew性能优化概述前言如何优化优化的本质卡顿的原因 CPU层级cell复用UITableVIew尽量采用复用 定义cell的种类尽量少&#xff0c;可以多用hidden缓存cell高度基础设置预先设置高度设置一个预先缓存 异步绘制滑动按照需加载尽量显示大小…...

【Linux网络与网络编程】09.传输层协议TCP

前言 TCP 即 传输控制协议 (Transmission Control Protocol)&#xff0c;该协议要对数据的传输进行一个详细的控制&#xff08;数据传输时什么时候传输&#xff0c;一次发多少&#xff0c;怎么发&#xff0c;出错了怎么办……&#xff09; 本篇博客将从下面这张TCP协议格式图…...

08.unity 游戏开发-unity编辑器资源的导入导出分享

08.unity 游戏开发-unity编辑器资源的导入导出分享 提示&#xff1a;帮帮志会陆续更新非常多的IT技术知识&#xff0c;希望分享的内容对您有用。本章分享的是Python基础语法。前后每一小节的内容是存在的有&#xff1a;学习and理解的关联性&#xff0c;希望对您有用~ unity简介…...

Docker Swarm 集群

Docker Swarm 集群 本文档介绍了 Docker Swarm 集群的基本概念、工作原理以及相关命令使用示例&#xff0c;包括如何在服务调度中使用自定义标签。本文档适用于需要管理和扩展 Docker 容器化应用程序的生产环境场景。 1. 什么是 Docker Swarm Docker Swarm 是用于管理 Docker…...

数据中台、数据湖和数据仓库 区别

1. 核心定义与定位 数据仓库&#xff08;Data Warehouse&#xff09; 定义&#xff1a;面向主题的、集成的、历史性且稳定的结构化数据集合&#xff0c;主要用于支持管理决策和深度分析。定位&#xff1a;服务于管理层和数据分析师&#xff0c;通过历史数据生成报表和商业智能…...

【CodeMirror】系列(二)官网示例(五)可撤销操作、拆分视图、斑马条纹

一、可撤销操作 默认情况下&#xff0c;history 历史记录扩展仅跟踪文档和选择的更改&#xff0c;撤销操作只会回滚这些更改&#xff0c;而不会影响编辑器状态的其他部分。 不过你也可以将其他的操作定义成可撤销的。如果把这些操作看作状态效果&#xff0c;就可以把相关功能整…...

SpringBoot 动态路由菜单 权限系统开发 菜单权限 数据库设计 不同角色对应不同权限

介绍 系统中的路由配置可以根据用户的身份、角色或其他权限信息动态生成&#xff0c;而不是固定在系统中。不同的用户根据其权限会看到不同的路由&#xff0c;访问不同的页面。对应各部门不同的权限。 效果 [{"id": 1,"menuName": "用户管理"…...

scikit-learn 开源框架在机器学习中的应用

文章目录 scikit-learn 开源框架介绍1. 框架概述1.1 基本介绍1.2 版本信息 2. 核心功能模块2.1 监督学习2.2 无监督学习2.3 数据处理 3. 关键设计理念3.1 统一API设计3.2 流水线(Pipeline) 4. 重要辅助功能4.1 模型选择4.2 评估指标 5. 性能优化技巧5.1 并行计算5.2 内存优化 6…...

GPT-4、Grok 3与Gemini 2.0 Pro:三大AI模型的语气、风格与能力深度对比

更新后的完整CSDN博客文章 以下是基于您的要求&#xff0c;包含修正后的幻觉率部分并保留原始信息的完整CSDN博客风格文章。幻觉率已调整为更符合逻辑的描述&#xff0c;其他部分保持不变。 GPT-4、Grok 3与Gemini 2.0 Pro&#xff1a;三大AI模型的语气、风格与能力深度对比 …...

Cyber Weekly #51

赛博新闻 1、英伟达开源新模型&#xff0c;性能直逼DeepSeek-R1 本周&#xff0c;英伟达开源了基于Meta早期Llama-3.1-405B-Instruct模型开发的Llama-3.1-Nemotron-Ultra-253B-v1大语言模型&#xff0c;该模型拥有2530亿参数&#xff0c;在多项基准测试中展现出与6710亿参数的…...