设计模式实践:模板方法、观察者与策略模式详解
目录
- 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 模板方法基本概念 定义:一个操作中的算法的骨架 &…...
Google的AI模型Gemini和Gemini网络协议
粉丝私信问我:gemini如何访问? "Gemini如何访问"需明确区分两种完全不同的技术体系:Google的AI模型Gemini和Gemini网络协议。以下是两者的访问方式详解: 一、访问Google的Gemini AI模型 1. 通过Web应用 地址…...
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+部署文档+讲解),源码可白嫖!
摘要 随着信息时代的来临,民宿过去的民宿信息方式的缺点逐渐暴露,对过去的民宿信息的缺点进行分析,采取计算机方式构建民宿信息系统。本文通过阅读相关文献,研究国内外相关技术,提出了一种民宿信息管理、民宿信息管理…...
使用OpenSceneGraph (osg)实现一个星系漫游
简介 使用OpenSceneGraph (osg)实现了一个太阳系漫游的程序,具有以下特点: 1.通过按键控制飞行器前进后退、空间姿态; 2.星系渲染; 3.背景星空渲染; 效果 提供了一张超大的星空背景图 代码示例 int main(int a…...
笔试专题(九)
文章目录 十字爆破(暴力)题解代码 比那名居的桃子(滑动窗口/前缀和)题解代码 分组(暴力枚举 优化二分)题解代码 十字爆破(暴力) 题目链接 题解 1. 暴力 预处理 2. 如果单纯的暴…...
sklearn决策树 待更新
注意:sklearn中所有的决策树模型包括回归决策树实现的是CART决策树算法,在官方文档中有介绍。sklearn中的决策树模型最终得到的树结构都是二叉树,因为CART算法生成的就是二叉树。 DecisionTreeClassifier类 如果待预测样本有多个类别具有相同…...
eino v0.3.21 重磅发布!节点中断控制+空值映射支持,AI应用开发再添神器!
CloudWeGo/eino v0.3.21 作为最新补丁版本,聚焦流程控制与数据映射两大核心场景,为AI应用与微服务开发者提供更灵活的调试能力与容错设计! 1. 节点中断控制(Feat: Node Interrupt) • 功能亮点:新增 node …...
力扣每日打卡 50. Pow(x, n) (中等)
[TOC](力扣 50. Pow(x, n) 中等) 前言 这是刷算法题的第十一天,用到的语言是JS 题目:力扣 50. Pow(x, n) (中等) 一、题目内容 实现 pow(x, n) ,即计算 x 的整数 n 次幂函数(即,xn )。 示例 1࿱…...
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(Field-Oriented Control,磁场定向控制) 中,arm_math.h、arm_const_structs.h 和 arm_common_tables.h 是 CMSIS-DSP 库的核心组件,用于实现高效的数学运算、预定义结构和查表操作。以下是它们在 FOC 控…...
每天五分钟深度学习:非线性激活函数的导数
本文重点 本文探讨了神经网络中几种常见非线性激活函数(Sigmoid、Tanh、ReLU、Leaky ReLU、ELU、Softmax)的导数特性。通过对各激活函数导数的数学推导与实际应用分析,揭示了不同激活函数在梯度传播、收敛速度及模型表达能力方面的差异。研究发现,ReLU及其变体在计算效率与…...
OpenHarmony5.0.2 USB摄像头适配
开发环境 OpenHarmony5.0.2 RK3568 USB摄像头 遇到问题 编译后插上USB摄像头后打开相机无图像 解决思路 5.0.2版本是支持USB摄像头的,需要修改默认的板载相机配置即可。 修改代码 1、修改配配置 文件地址:vendor/hihope/rk3568/hdf_config/uhdf…...
vue: router基础用法
router基础用法 1.安装router2.配置router3.路由编程1.编程式导航2.声明式导航 1.安装router 在node环境下,直接运行 npm install router42.配置router 创建文件夹并命名为router 在router文件夹中创建index.js index.js示例配置如下: import { creat…...
IDE中使用Spring Data Redis
步骤一:导入Spring Data Redis的maven坐标 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency> 步骤二:配置Redis数据源 步骤三&…...
【计网】网络交换技术之报文交换(复习自用,了解,重要3)
复习自用的,处理得比较草率,复习的同学或者想看基础的同学可以看看,大佬的话可以不用浪费时间在我的水文上了 另外两种交换技术可以直接点击链接访问相关笔记: 电路交换 分组交换 一、报文交换的定义 报文交换(Me…...
GitLab 17.x 配置 https
文章目录 使用外部 nginx 参考:https://docs.gitlab.com/omnibus/settings/nginx.html 使用内置 nginx 参考: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为解决其内部数据分析需求而开发,并于2016年开源。专为大规模数据分析,实时数据分析和复杂查询设计,具有高性能、实时数据和可扩展性等…...
【编写Node接口;接口动态获取VUE文件并异步加载, 并渲染impoort插件使用】
编写Node接口;接口动态获取VUE文件并异步加载, 并渲染impoort插件使用; vue3-sfc-loader主要特征: 编写Node接口:Vue2项目使用:Vue3项目使用:(页面按需加载插件、图片等)主要使用&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 协议的自动化任务实现
好的!以下是基于我们讨论的关于 MCP 协议、JSON 数据交互以及自然语言到 JSON 转换的实现过程的总结,格式化为一篇 CSDN 风格的博客记录。这篇文章将记录你的发现,适合分享给技术社区。 从自然语言到 JSON 数据交互:探索 MCP 协议…...
n8n 本地部署及实践应用,实现零成本自动化运营 Telegram 频道(保证好使)
n8n 本地部署及实践应用,实现零成本自动化运营 Telegram 频道(保证好使) 简介 n8n 介绍 一、高度可定制性 二、丰富的连接器生态 三、自托管部署(本地部署) 四、社区驱动 n8n 的部署 一、前期准备 二、部署步…...
嵌入式学习(37)-STM32串口发送中断的实现
一、概述 项目中需要用到发送中断,所以了解了发送中断的一些知识。 二、应用 状态寄存器USART_SR的复位值为0x00C0H, 也就是第七位TXE和第六位TC复位值为1,而TXE1,表明发送数据寄存器为空, TC1表明发送已完成。 USART_ITConfig(USART1, USA…...
Android envsetup与Python venv使用指南
Android envsetup 和 Python venv 是两种完全不同的环境配置工具,分别服务于不同的开发场景。以下是对它们的详细解释及使用方法: 1. Android envsetup 用途: Android envsetup 是 Android 源码开发中的环境配置脚本(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效果提升有重要作用,但是在openAI o1和DeepSeek R1 technical report上都没有详细的实验细节。本文主要提出了DAPO算法,提出了4个关键技术点并开源参数和代码。在AIME 2024验证了DAPO算法的有效性。 2. Tricks Exc…...
五子棋(测试报告)
文章目录 一、项目介绍二、测试用例三、自动化测试用例的部分展示注册登录游戏大厅游戏匹配 总结 一、项目介绍 本项目是一款基于Spring、SpringMVC、MyBatis、WebSocket的双人实时对战五子棋游戏,游戏操作便捷,功能清晰明了。 二、测试用例 三、自动化测试用例的…...
【小工具】定时任务执行器
定时任务执行器 背景版本代码JobJob执行机 背景 有时我们的项目内需要一个定时执行器来执行某些任务,就需要一个简单好用的定时任务机。 注意,这个定时任务机并不原生支持分布式,如果需要分布式的功能请自己实现。 版本 jdk21 代码 Job …...
LVGL源码(7):渲染
在LVGL源码(4):LVGL关于EVENT事件的响应逻辑_lvgl实现显示打车-CSDN博客这篇文章中,我们提到了LVGL的三大步骤:检测用户输入操作、调用我们编写的逻辑、在屏幕上显示对应的画面;而在学习完“样式”之后,我们或许可以将上述步骤说明…...
02_通过调用硅基流动平台deepseekapi按输入的标题生成文章
from openai import OpenAIclient OpenAI(base_urlhttps://api.siliconflow.cn/v1,api_keyyou api-key )# 定义关键词变量 keyword "人性的弱点都有哪些?"# 发送带有流式输出的请求 response client.chat.completions.create(model"deepseek-ai/D…...
三、Virtual Device Manager
一、创建AVD AVD是Android Virtual Device(安卓虚拟设备),我们可以启动Android Studio 选择 Virtual Device Manager 创建并启动一个模拟器。 二、设置屏幕大小 上面直接创建的镜像是不能设置屏幕大小的,启动后笔记本屏幕都放不下ÿ…...
MATLAB2022b安装
1 从百度网盘下载MATLAB2022b,下载完成后解压到某个文件夹; 链接: MATLAB2022b 提取码: 6666 2 打开解压后的文件夹,进入setup文件夹,双击打开“setup.exe”文件; 3 在弹出窗口中选择“高级选项”-->“我有文件安…...
计算机编码
计算机,不能直接存储文字,存储的是编码。 计算机只能处理二进制的数据,其它数据,比如:0-9、a-z、A-Z,这些字符,我们可以定义一套规则来表示。假如:A用110表示,B用111表示…...
Dell EMC Unity NAS 认证方式介绍
近日有个客户要配置EMC Unity的NAS访问,我们知道NAS有Linux环境下的NFS和Windows环境下的SMB(也叫做CIFS)。单独配置其中的一种访问协议相对简单,但是客户提出的要求是要对文件系统同时NFS和SMB访问,这就有些复杂&…...
SpringAi 会话记忆功能
在使用chatGPT,豆包等产品后,就会发现他们的会话有“记忆”功能。 那么我们用API接口的话,这个是怎么实现的呢? 属于比较粗暴的方式,把之前的内容与新的提示词一起再次发给大模型。让我们看到他们有记忆功能。 下面介绍…...
BUUCTF-web刷题篇(25)
34.the mystery of ip 给出链接,输入得到首页: 有三个按钮,flag点击后发现页面窃取客户端的IP地址,通过给出的github代码中的php文件发现可以通过XFF或Client-IP传入值。使用hackbar或BP 使用XSS,通过github给出的目录…...
Elasticsearch 性能优化:从原理到实践的全面指南
Elasticsearch(ES)作为一款基于 Lucene 的分布式搜索和分析引擎,广泛应用于日志分析、搜索引擎和实时数据处理等场景。然而,在高并发、大数据量环境下,Elasticsearch 的性能可能面临瓶颈,如查询延迟高、索引…...
UITableVIew性能优化概述
UITableVIew性能优化概述 文章目录 UITableVIew性能优化概述前言如何优化优化的本质卡顿的原因 CPU层级cell复用UITableVIew尽量采用复用 定义cell的种类尽量少,可以多用hidden缓存cell高度基础设置预先设置高度设置一个预先缓存 异步绘制滑动按照需加载尽量显示大小…...
【Linux网络与网络编程】09.传输层协议TCP
前言 TCP 即 传输控制协议 (Transmission Control Protocol),该协议要对数据的传输进行一个详细的控制(数据传输时什么时候传输,一次发多少,怎么发,出错了怎么办……) 本篇博客将从下面这张TCP协议格式图…...
08.unity 游戏开发-unity编辑器资源的导入导出分享
08.unity 游戏开发-unity编辑器资源的导入导出分享 提示:帮帮志会陆续更新非常多的IT技术知识,希望分享的内容对您有用。本章分享的是Python基础语法。前后每一小节的内容是存在的有:学习and理解的关联性,希望对您有用~ unity简介…...
Docker Swarm 集群
Docker Swarm 集群 本文档介绍了 Docker Swarm 集群的基本概念、工作原理以及相关命令使用示例,包括如何在服务调度中使用自定义标签。本文档适用于需要管理和扩展 Docker 容器化应用程序的生产环境场景。 1. 什么是 Docker Swarm Docker Swarm 是用于管理 Docker…...
数据中台、数据湖和数据仓库 区别
1. 核心定义与定位 数据仓库(Data Warehouse) 定义:面向主题的、集成的、历史性且稳定的结构化数据集合,主要用于支持管理决策和深度分析。定位:服务于管理层和数据分析师,通过历史数据生成报表和商业智能…...
【CodeMirror】系列(二)官网示例(五)可撤销操作、拆分视图、斑马条纹
一、可撤销操作 默认情况下,history 历史记录扩展仅跟踪文档和选择的更改,撤销操作只会回滚这些更改,而不会影响编辑器状态的其他部分。 不过你也可以将其他的操作定义成可撤销的。如果把这些操作看作状态效果,就可以把相关功能整…...
SpringBoot 动态路由菜单 权限系统开发 菜单权限 数据库设计 不同角色对应不同权限
介绍 系统中的路由配置可以根据用户的身份、角色或其他权限信息动态生成,而不是固定在系统中。不同的用户根据其权限会看到不同的路由,访问不同的页面。对应各部门不同的权限。 效果 [{"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博客文章 以下是基于您的要求,包含修正后的幻觉率部分并保留原始信息的完整CSDN博客风格文章。幻觉率已调整为更符合逻辑的描述,其他部分保持不变。 GPT-4、Grok 3与Gemini 2.0 Pro:三大AI模型的语气、风格与能力深度对比 …...
Cyber Weekly #51
赛博新闻 1、英伟达开源新模型,性能直逼DeepSeek-R1 本周,英伟达开源了基于Meta早期Llama-3.1-405B-Instruct模型开发的Llama-3.1-Nemotron-Ultra-253B-v1大语言模型,该模型拥有2530亿参数,在多项基准测试中展现出与6710亿参数的…...