c++ 设计模式 的课本范例(下)
(19) 桥接模式 Bridge,不是采用类继承,而是采用类组合,一个类的数据成员是类对象,来扩展类的功能。源码如下:
class OS // 操作系统负责绘图
{
public:virtual ~OS() {}virtual void draw(char * ptrCache , int lengthCache) = 0 ;
};class OS_Window : public OS
{
public:void draw(char* ptrCache, int lengthCache) { cout << " windows 下绘图\n\n"; }
};class OS_Linux : public OS
{
public:void draw(char* ptrCache, int lengthCache) { cout << " Linux 下绘图\n\n"; }
};class Image // 本基类有成员函数负责解析与加载图片至缓存,但绘图调用跟操作系统有关的底层函数
{
protected: OS * ptrOS;
public:virtual ~Image() {}Image(OS* p) : ptrOS(p) {}virtual void parseImage( const char * name) = 0;
};class Image_jpg : public Image
{
public:Image_jpg(OS * p) : Image(p){}void parseImage(const char* name){cout << " 解析 jpg 图片 , ";char c[100]; // 假定分析 jpg 格式后的图片信息统一用 100 字节存储。ptrOS->draw(c , 100);}
};class Image_png : public Image
{
public:Image_png(OS* p) : Image(p) {}void parseImage( const char* name){cout << " 解析 png 图片 , ";char c[50]; // 假定分析 png 格式后的图片信息统一用 50 字节存储。ptrOS->draw(c, 50);}
};int main()
{OS_Window osWindow;OS_Linux osLinux;Image_jpg jpgA(&osLinux) , jpgB(&osWindow) ;Image_png pngA(&osLinux) , pngB(&osWindow) ;jpgA.parseImage("aaa"); jpgB.parseImage("b");pngA.parseImage("c");pngB.parseImage("dd");return 0;
}
测试结果如下:

(20)中介者模式 Mediator 。比如 UI 设计,页面上的各种控件,牵一发而动全身,彼此联系紧密。若把控件间的联系代码写入各个控件,会很繁琐,庞大。因此可以创建一个中介对象,专门处理当一个 UI 控件的状态变化时的逻辑。也像电脑主板上的总线,借着总线,实现电脑各部件见的连接与通信。以下代码配套的是这个 UI 登录界面:

配套的代码如下:
class Control; // 类的前向声明class Media // 中介者的基类
{
public:virtual ~Media() {}virtual void changed(Control * ptrCtrl) = 0;
};class Control // 控件的基类
{
protected: string name; // 控件名称,以此区分控件,所以该名称将是唯一的Media* ptrMedia; // 显示本控件属于哪个中介管理
public:virtual ~Control() {}Control(const string& s, Media* pM) : name(s), ptrMedia(pM) {}virtual void enable(bool enabled) = 0;virtual void changed() { ptrMedia->changed(this); } // 控件产生了变化,交由 中介者 来处理这种相关联的变化
};class Control_Button : public Control
{
public:Control_Button(const string& s, Media* ptr) : Control(s, ptr) {}void enable(bool enabled){ if (enabled)cout << " 按钮 " << name << " 被启用\n\n";elsecout << " 按钮 " << name << " 被禁用\n\n";}
};class Control_Radio : public Control
{
public:Control_Radio(const string& s, Media* ptr) : Control(s, ptr) {}void enable(bool enabled) {} // 对于单选按钮,不必使用此函数void select(bool clicked) // 对于单选按钮,增加此函数{if(clicked)cout << " 单选按钮 " << name << " 被启用\n\n";elsecout << " 单选按钮 " << name << " 被禁用\n\n";}
};class Control_text : public Control
{
private : string text; // 文本框里保存了账号或密码的内容
public:Control_text(const string & t , const string& s, Media* ptr) : text(t) , Control(s, ptr) {}Control_text(const string& s, Media* ptr) : text(""), Control(s, ptr) {}void enable(bool enabled){if (enabled)cout << " 文本框 " << name << " 被启用\n\n";elsecout << " 文本框 " << name << " 被禁用\n\n";}void setText(const string& s) { text = s; } // 对文本框增加此函数bool isEmpty() { return text.empty(); } // 判断文本框是否为空
};class Media_UI : public Media
{
private:Control_Button* pLogin, * pLogout;Control_Radio* pRadioTourist, * pRadioAccount;Control_text *pTextName, * pTextPwd;
public:Media_UI(){}void init(Control_Button* pLin, Control_Button*pLout, Control_Radio* pTourist, Control_Radio* pAccount, Control_text* pName, Control_text* pPwd){pLogin = pLin; pLogout = pLout;pRadioTourist = pTourist; pRadioAccount = pAccount;pTextName = pName; pTextPwd = pPwd;}virtual void changed(Control* ptrCtrl){if (ptrCtrl == pLogout) { cout << " 游戏退出!\n\n"; return; }if (ptrCtrl == pRadioTourist){pRadioTourist->select(true);pRadioAccount->select(false);pTextName->enable(false);pTextPwd->enable(false);pLogin->enable(true);return;}if (ptrCtrl == pLogin) { cout << " 开始登录验证\n\n"; }if (ptrCtrl == pRadioAccount){pRadioTourist->select(false);pRadioAccount->select(true);pTextName->enable(true);pTextPwd->enable(true);if (pTextName->isEmpty() || pTextPwd->isEmpty())pLogin->enable(false);elsepLogin->enable(true);}if (ptrCtrl == pTextName || ptrCtrl == pTextPwd){if (pTextName->isEmpty() || pTextPwd->isEmpty())pLogin->enable(false);elsepLogin->enable(true);}}
};int main()
{Media_UI media_UI;Control_Button login("登录", &media_UI), logout("退出" , &media_UI);Control_Radio tourist("游客登录", &media_UI), account("账户登录" , &media_UI);Control_text name("昵称", &media_UI), password("密码" , &media_UI);media_UI.init(&login , &logout , & tourist , & account , & name , & password);login.changed(); logout.changed();tourist.changed(); account.changed();name.changed(); password.changed();name.setText("aaa"); password.setText("1234556");login.changed(); account.changed(); name.changed();return 0;
}
测试结果如下:

(21) 备忘录模式 Memento , 也可以翻译为更简单的 Note 。例如游戏里在某个时刻保存玩家的当时信息。
class Fighter; class Note // 备忘录模式
{
private:int life, magic, attack;friend Fighter; // 本类对 Fighter 类开放所有权限Note(int life, int m, int a) :life(life), magic(m), attack(a) {} // 私有的构造函数int getLife() { return life; }int getMagic() { return magic; }int getAttack() { return attack; }void setLife(int t) { life = t; }void setMagic(int t) { magic = t; }void setAttack(int t) { attack = t; }
public:};class Fighter
{
private:int life, magic, attack;
public:Fighter(int life, int m, int a) :life(life), magic(m), attack(a) {}Note* createNote() { return new Note(life ,magic , attack); } // 此处返回去的指针要记得回收内存,可以用智能指针包装下;void restoreFromNote(Note* ptr) { life = ptr->life; magic = ptr->magic; attack = ptr->attack; }void show() {cout << " 玩家当前的 life , magic , attack : " << life << " " << magic << " " << attack << '\n';}void setStatus() { life /= 2; magic /= 2; attack /= 2; }
};int main()
{Fighter f(100,200,300);unique_ptr<Note> uniNote(f.createNote());f.show();f.setStatus();f.show();f.restoreFromNote(uniNote.get());f.show();return 0;
}
测试结果如下:

( 22) 责任链模式 Chain Of Responsibility 。比如员工的加薪申请,申请的金额越大,就越需要更高层的领导审批。可以把负责审批的管理,创建为一个个对象,并把它们串起来。
class RaiseRequest // 本类的含义是来自某个人的加薪请求
{
private:string name;int request;
public:RaiseRequest(const string& s, int t) : name(s), request(t) {}int getRequest() const { return request; } // 这里的 const 不能省略,const 修饰的是 this
};class Manager // 可以审批加薪请求的领导
{
private:Manager* next = nullptr;
public:virtual ~Manager() {}void setChain(Manager* n) { next = n; }Manager* getNext() { return next; }virtual void processRequest(const RaiseRequest& raiReq) = 0;
};class Manager_Low : public Manager
{
public:virtual void processRequest(const RaiseRequest& raiReq){auto t = raiReq.getRequest();if (t < 5000)cout << " 加薪请求 " << t << " 已被低级管理处理\n\n";else if (getNext())getNext()->processRequest(raiReq);elsecout << " 没有合适的管理;来处理此加薪请求\n\n";}
};class Manager_High : public Manager
{
public:virtual void processRequest(const RaiseRequest& raiReq){auto t = raiReq.getRequest();if ( t >= 5000 && t < 10000)cout << " 加薪请求 " << t << " 已被高级管理处理\n\n";else if (getNext())getNext()->processRequest(raiReq);elsecout << " 没有合适的管理来处理此 " << t << " 的加薪请求\n\n";}
};int main()
{Manager_Low mL;Manager_High mH;mL.setChain(&mH);RaiseRequest a("zhangsan" , 500) , b("Lisi" , 6000) , c("wangWu" , 13000);mL.processRequest(a);mL.processRequest(b);mL.processRequest(c);return 0;
}
测试结果如下:

以上的责任链中,只需要有一个链节处理事务即可,叫单纯责任链。但换个场景,比如网络用语过滤,需要进行性 、脏话 、 政治敏感词,多重过滤,就叫非单纯的责任链模式,链中的每个链节都要被调用,处理事务。
class Filter // 过滤器过滤文本,以使文本文明
{
private:Filter* next = nullptr;
public:virtual ~Filter() {}void setChain(Filter* n) { next = n; }Filter* getNext() { return next; }virtual void processRequest(string& str) = 0; // 以形参引用带回返回值
};class Filter_Sexy : public Filter // 过滤性敏感词
{
public:virtual void processRequest(string& str){cout << " sexy 敏感被处理\n\n";str += "XXX";if(getNext())getNext()->processRequest(str);}
};class Filter_Policy : public Filter // 过滤政治敏感词
{
public:virtual void processRequest(string& str){cout << " policy 敏感被处理\n\n";str += "ZZZ";if (getNext())getNext()->processRequest(str);}
};int main()
{Filter_Sexy fSex;Filter_Policy fPlcy;fSex.setChain(&fPlcy);string s(" 测试文字 ");fSex.processRequest(s);cout << " 最终的测试文字: " << s << "\n\n";return 0;
}
测试结果如下:

(23) 访问者模式 Visitor 。此模式是为了解决如下案例的编码:

某人去看病,大夫列了一个药品单。这些药品就是一个个被访问的对象。这些对象会被不同的人访问。收费处要根据药的价格收费,药房根据药名取药,营养师根据药制定食谱,健身教练根据药制定训练方案。这里引入双重分派机制(double dispatch):谁被访问,又是谁来访问。非常贴合访问者模式。以下给出代码例子与测试结果。
class Visitor;class Medicine
{
public:virtual ~Medicine() {}virtual string getName() = 0;virtual double getPrice() = 0;virtual void accept(Visitor* visitor) = 0;
};class Medicine_Eye : public Medicine
{
public:virtual string getName() { return " 眼药 "; }virtual double getPrice() { return 10.5; }virtual void accept(Visitor* visitor); // 这一步声明不可少,不然报错,而且与上面的 = 0 ,还不一样
};class Medicine_Nose : public Medicine
{
public:virtual string getName() { return " 鼻药 "; }virtual double getPrice() { return 100.5; }virtual void accept(Visitor* visitor); // 这一步声明不可少
};class Visitor
{
public:virtual ~Visitor() {}virtual void visit_MediEye(Medicine_Eye * mediEye) = 0; virtual void visit_MediNose(Medicine_Nose * mediNose) = 0;
};class Visitor_Charge : public Visitor // 收费人员
{
private: double totalPrice = 0;
public:void visit_MediEye(Medicine_Eye* mediEye){totalPrice += mediEye->getPrice();cout << " 收费人员统计药品 " << mediEye->getName() << " ,价格为: " << mediEye->getPrice() << "\n\n";}void visit_MediNose(Medicine_Nose* mediNose){totalPrice += mediNose->getPrice();cout << " 收费人员统计药品 " << mediNose->getName() << " ,价格为: " << mediNose->getPrice() << "\n\n";}double getTotalPrice() { return totalPrice; }
};class Visitor_Distribute : public Visitor // 收费人员
{
public:void visit_MediEye(Medicine_Eye* mediEye){cout << " 药房人员分发药品 " << mediEye->getName() << "\n\n";}void visit_MediNose(Medicine_Nose* mediNose){cout << " 药房人员分发药品 " << mediNose->getName() << "\n\n";}
};class Visitor_Trainer : public Visitor
{
public:void visit_MediEye(Medicine_Eye* mediEye){cout << " 健身教练认为要做眼保健操\n\n";}void visit_MediNose(Medicine_Nose* mediNose){cout << " 健身教练认为要多跑步\n\n";}
};void Medicine_Eye ::accept(Visitor* visitor) { visitor->visit_MediEye(this); }
void Medicine_Nose::accept(Visitor* visitor) { visitor->visit_MediNose(this); }int main()
{Medicine_Eye mediEye;Medicine_Nose mediNose;Visitor_Charge visiCharge;Visitor_Distribute visiDistri;Visitor_Trainer visiTrainer;mediEye.accept(&visiCharge);mediEye.accept(&visiDistri);mediEye.accept(&visiTrainer);cout << " -------------------------------\n\n";mediNose.accept(&visiCharge);mediNose.accept(&visiDistri);mediNose.accept(&visiTrainer);cout << " 总的药钱: " << visiCharge.getTotalPrice() << endl;return 0;
}
测试结果如下:

(24) 解释器模式 Interpreter 。一门计算机语言,必须背后有一个匹配的编译器对其支持,将其翻译为机器语言,此门新的编程语言才是有效的。编译器模式就是讲如何为一门语言编写匹配的编译器。为举例简单,规定本语言只支持整数的加减运算,没有括号,且表示整数的字符必须是单个的英文字母。整数与加减运算符之间,书写的时候不留空格。因为为语言编写编译器具有类似的地方,故称其为一种模式。
以下是例子代码:
#include<xstring>
#include<map>
#include<stack>class Node // 对语言翻译的结果是将其组织成语法树。故需要定义树节点的结构
{
public:char type; // 节点类型,取值: v + -virtual ~Node() {}Node(char c) : type(c) {}virtual int interpret(map<char , int>& mapVar) = 0; // 形参对运算符节点没用,但对整数节点有用,返回变量名对应的值
};class Node_Var : public Node // 变量节点
{
private : char varName ;
public:Node_Var(char name, char type) : varName(name), Node(type) {}int interpret( map<char, int>& mapVar) { return mapVar[varName]; }
};class Node_Symbol : public Node // 运算符节点的父类
{
protected : Node* ptrLeft, * ptrRight;
public:Node_Symbol(Node* left, Node* right, char type) : ptrLeft(left), ptrRight(right), Node(type) {}Node* getLeftChild() { return ptrLeft; }Node* getRightChild() { return ptrRight; }
};class Node_Add : public Node_Symbol // 加号运算符
{
public:Node_Add(Node* left, Node* right, char type) : Node_Symbol(left , right , type) {}virtual int interpret(map<char, int>& mapVar) // 本函数可以被递归调用,返回左子树与右子树的值的和{return ptrLeft->interpret(mapVar) + ptrRight->interpret(mapVar);}
};class Node_Sub : public Node_Symbol // 减号运算符
{
public:Node_Sub(Node* left, Node* right, char type) : Node_Symbol(left, right, type) {}virtual int interpret(map<char, int>& mapVar) // 本函数可以被递归调用,返回左子树与右子树的值的差{return ptrLeft->interpret(mapVar) - ptrRight->interpret(mapVar);}
};Node* buildTree(string& expr) // #include<stack>
{stack<Node* > stackNode; // 这个栈很有作用Node* ptrLeft = nullptr, * ptrRight = nullptr;for (int i = 0; i < expr.size(); i++)switch (expr[i]){case '+':ptrLeft = stackNode.top();++i;ptrRight = new Node_Var(expr[i], 'v');stackNode.push( new Node_Add(ptrLeft , ptrRight , '+') );break;case '-':ptrLeft = stackNode.top();++i;ptrRight = new Node_Var(expr[i], 'v');stackNode.push(new Node_Sub(ptrLeft, ptrRight, '-'));break;default:stackNode.push( new Node_Var(expr[i] , 'v') );break;}return stackNode.top();
}void release(Node * node) // 回收语法树占据的内存,可能被递归调用
{if (node->type == 'v')delete node;else{release(((Node_Symbol*)node)->getLeftChild() );release(((Node_Symbol*)node)->getRightChild() );delete node;}
}int main()
{string expr("a-b+c+d");map<char, int> mapVar;mapVar.insert(pair('a' , 7));mapVar.insert(pair('b' , 9));mapVar.insert(pair('c' , 3));mapVar.insert(pair('d' , 2));Node* root = buildTree(expr);cout << " 表达式为: " << expr << "\n\n";cout << " 结果为 : " << root->interpret(mapVar) << "\n\n";release(root);return 0;
}
测试结果如下:

接着为本解释器模式再举一例。机器人控制,为此创建一门语言,我们可以使用如下 的语句: left walk 15 and up run 20 。
该语言有如下几个关键字 : left 、 right 、 up 、 down ,表示运动的方向; walk 、 run 表示运动的方式 , 整数表示运动的距离;and 表示衔接两个运动。用空格分隔关键字。我们为其创建解释器。
#pragma warning(disable : 4996) // 必须要有,要不 strcpy 与 strtok 都会报错#include<string>
#include<xstring>
#include<map>
#include<stack>
#include<vector>class Node
{
public:virtual ~Node() {}virtual string interpret() = 0;
};class Node_Direction : public Node
{
private: string direction;
public:Node_Direction(const string& s) : direction(s) {}virtual string interpret(){if (direction == "left") return "向左";else if (direction == "right") return "向右";else if (direction == "up") return "向上";else if (direction == "down") return "向下";else return "方向错误";}
};class Node_mode : public Node // walk or run
{
private: string mode;
public:Node_mode(const string& s) : mode(s) {}virtual string interpret(){if (mode == "walk") return "走步";else if (mode == "run") return "跑步";else return "动作错误";}
};class Node_Distance : public Node // 距离
{
private: string distance;
public:Node_Distance(const string& s) : distance(s) {}virtual string interpret() { return " " + distance + " 米 "; }
};class Node_Sentence : public Node
{
private:Node* ptrDistance; // 这里用父类指针,指向子类对象,否则报错Node* ptrDirection;Node* ptrMode;
public:Node_Sentence(Node* pDirect, Node* pMode, Node* pDistance) : ptrDirection(pDirect), ptrMode(pMode), ptrDistance(pDistance) {}Node* getDirection() { return ptrDirection; }Node* getMode() { return ptrMode; }Node* getDistance() { return ptrDistance; }virtual string interpret(){return ptrDirection->interpret() + ptrMode->interpret() + ptrDistance->interpret() ;}
};class Node_And : public Node
{
private:Node* ptrLeft , * ptrRight;
public:Node_And(Node* pL, Node* pR) : ptrLeft(pL), ptrRight(pR) {}Node* getLeft() { return ptrLeft; }Node* getRight() { return ptrRight; }virtual string interpret() { return ptrLeft->interpret() + " 又 " + ptrRight->interpret(); }
};Node* buidTree(string & expr)
{stack<Node*> stackNode;vector<string> vecStr;Node* pDirection = nullptr, * pMode = nullptr, * pDistence = nullptr, * pLeft = nullptr, * pRight = nullptr;char* cache = new char[expr.size() + 1 ];strcpy(cache , expr.c_str());char* pstrChild = strtok(cache , " ");while (pstrChild){vecStr.push_back(string(pstrChild)); // 把原来的语句拆分成了一个个语法节点pstrChild = strtok(NULL , " ");}delete[] cache;for( auto iter = vecStr.begin() ; iter != vecStr.end() ; iter++ )if (*iter == "and"){pLeft = stackNode.top();++iter;pDirection = new Node_Direction(*iter);++iter;pMode = new Node_mode(*iter);++iter;pDistence = new Node_Distance(*iter);pRight = new Node_Sentence(pDirection, pMode, pDistence);stackNode.push(new Node_And(pLeft , pRight));}else{pDirection = new Node_Direction(* iter);++iter;pMode = new Node_mode(* iter);++iter;pDistence = new Node_Distance(* iter);stackNode.push(new Node_Sentence(pDirection , pMode , pDistence));}return stackNode.top();
}void release(Node* ptr) // 本函数也会被递归调用
{Node_And* pAnd = dynamic_cast<Node_And*>(ptr);if (pAnd){release(pAnd->getLeft()) ;release(pAnd->getRight());}else{Node_Sentence* pSentance = dynamic_cast<Node_Sentence*>(ptr);if (pSentance){release(pSentance->getDirection());release(pSentance->getMode());release(pSentance->getDistance());}}delete ptr;
}int main()
{string expr("right walk 15 and up run 30");Node* ptrRoot = buidTree(expr);cout << " 机器人控制代码为: " << expr << "\n\n";cout << " 解释器解释后: " << ptrRoot->interpret() << "\n\n";release(ptrRoot);return 0;
}
测试结果如下:

经 MFC 框架测试,没有内存泄露:

至此,王老师的 《c++ 设计模式》 的课本例子,已抄写完毕,谢谢王老师。
谢谢
相关文章:
c++ 设计模式 的课本范例(下)
(19) 桥接模式 Bridge,不是采用类继承,而是采用类组合,一个类的数据成员是类对象,来扩展类的功能。源码如下: class OS // 操作系统负责绘图 { public:virtual ~OS() {}virtual void draw(cha…...
结合数据索引结构看SQL的真实执行过程
引言 关于数据库设计与优化的前几篇文章中,我们提到了数据库设计优化应该遵守的指导原则、数据库底层的索引组织结构、数据库的核心功能组件以及SQL的解析、编译等。这些其实都是在为SQL的优化、执行的理解打基础。 今天这篇文章,我们以MySQL中InnoDB存…...
spark shuffle——shuffle管理
ShuffleManager shuffle系统的入口。ShuffleManager在driver和executor中的sparkEnv中创建。在driver中注册shuffle,在executor中读取和写入数据。 registerShuffle:注册shuffle,返回shuffleHandle unregisterShuffle:移除shuff…...
HTMLCSS(入门)
HTML <html> <head><title>第一个页面</title></head><body>键盘敲烂,工资过万</body> </html> <!DOCTYPE>文档类型声明,告诉浏览器使用哪种HTML版本显示网页 <!DOCTYPE html>当前页面采取…...
富格林:曝光可信策略制止亏损
富格林指出,相信大家都对黄金投资的价值空间有目共睹,现如今黄金市场波动频繁,因此不少投资者也开始加入该市场试图赢得额外的财富。但作为新手投资者贸贸然地进场操作,亏损的几率是很大的,因此要学会掌握正规平台曝光…...
Android --- Service
出自于此,写得很清楚。关于Android Service真正的完全详解,你需要知道的一切_android service-CSDN博客 出自【zejian的博客】 什么是Service? Service(服务)是一个一种可以在后台执行长时间运行操作而没有用户界面的应用组件。 服务可由其他应用组件…...
Vue3从入门到精通(三)
vue3插槽Slots 在 Vue3 中,插槽(Slots)的使用方式与 Vue2 中基本相同,但有一些细微的差异。以下是在 Vue3 中使用插槽的示例: // ChildComponent.vue <template><div><h2>Child Component</h2&…...
【FreeRTOS】同步与互斥通信-有缺陷的互斥案例
目录 同步与互斥通信同步与互斥的概念同步与互斥并不简单缺陷分析汇编指令优化过程 - 关闭中断时间轴分析 思考时刻 参考《FreeRTOS入门与工程实践(基于DshanMCU-103).pdf》 同步与互斥通信 同步与互斥的概念 一句话理解同步与互斥:我等你用完厕所,我再…...
Docker 安装 Python
Docker 安装 Python 在当今的软件开发领域,Docker 已成为一项关键技术,它允许开发人员将应用程序及其依赖环境打包到一个可移植的容器中。Python,作为一种广泛使用的高级编程语言,经常被部署在 Docker 容器中。本文将详细介绍如何在 Docker 中安装 Python,以及如何配置环…...
外泌体相关基因肝癌临床模型预测——2-3分纯生信文章复现——4.预后相关外泌体基因确定单因素cox回归(2)
内容如下: 1.外泌体和肝癌TCGA数据下载 2.数据格式整理 3.差异表达基因筛选 4.预后相关外泌体基因确定 5.拷贝数变异及突变图谱 6.外泌体基因功能注释 7.LASSO回归筛选外泌体预后模型 8.预后模型验证 9.预后模型鲁棒性分析 10.独立预后因素分析及与临床的…...
C++: Map数组的遍历
在C中,map是一个关联容器,它存储的元素是键值对(key-value pairs),其中每个键都是唯一的,并且自动根据键来排序。遍历map的方式有几种,但最常用的两种是使用迭代器(iterator…...
【Windows】Bootstrap Studio(网页设计)软件介绍及安装步骤
软件介绍 Bootstrap Studio 是一款专为前端开发者设计的强大工具,主要用于快速创建现代化的响应式网页和网站。以下是它的主要特点和功能: 直观的界面设计 Bootstrap Studio 提供了直观的用户界面,使用户能够轻松拖放元素来构建网页。界面…...
二维舵机颜色追踪,使用树莓派+opencv+usb摄像头+两个舵机实现颜色追踪,采用pid调控
效果演示 二维云台颜色追踪 使用树莓派opencvusb摄像头两个舵机实现颜色追踪,采用pid调控 import cv2 import time import numpy as np from threading import Thread from servo import Servo from pid import PID# 初始化伺服电机 pan Servo(pin19) tilt Serv…...
c进阶篇(四):内存函数
内存函数以字节为单位更改 1.memcpy memcpy 是 C/C 中的一个标准库函数,用于内存拷贝操作。它的原型通常定义在 <cstring> 头文件中,其作用是将一块内存中的数据复制到另一块内存中。 函数原型:void *memcpy(void *dest, const void…...
新手入门:无服务器函数和FaaS简介
无服务器(Serverless)架构的价值在于其成本效益、弹性和扩展性、简化的开发和部署流程、高可用性和可靠性以及使开发者能够专注于业务逻辑。通过自动化资源调配和按需计费,无服务器架构能够降低成本并适应流量变化,同时简化开发流…...
基于Transformer的端到端的目标检测 | 读论文
本文正在参加 人工智能创作者扶持计划 提及到计算机视觉的目标检测,我们一般会最先想到卷积神经网络(CNN),因为这算是目标检测领域的开山之作了,在很长的一段时间里人们都折服于卷积神经网络在图像处理领域的优势&…...
6.8应用进程跨网络通信
《计算机网络》第7版,谢希仁 理解socket通信...
redis布隆过滤器原理及应用场景
目录 原理 应用场景 优点 缺点 布隆过滤器(Bloom Filter)是一种空间效率很高的随机数据结构,它利用位数组和哈希函数来判断一个元素是否存在于集合中。 原理 数据结构: 位数组:一个由0和1组成的数组,初始…...
vue+openlayers之几何图形交互绘制基础与实践
文章目录 1.实现效果2.实现步骤3.示例页面代码3.基本几何图形绘制的关键代码 1.实现效果 绘制点、线、多边形、圆、正方形、长方形 2.实现步骤 引用openlayers开发库。加载天地图wmts瓦片地图。在页面上添加几何图形绘制的功能按钮,使用下拉列表(sel…...
「多模态大模型」解读 | 突破单一文本模态局限
编者按:理想状况下,世界上的万事万物都能以文字的形式呈现,如此一来,我们似乎仅凭大语言模型(LLMs)就能完成所有任务。然而,理想很丰满,现实很骨感——数据形态远不止文字一种&#…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
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": …...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
智能职业发展系统:AI驱动的职业规划平台技术解析
智能职业发展系统:AI驱动的职业规划平台技术解析 引言:数字时代的职业革命 在当今瞬息万变的就业市场中,传统的职业规划方法已无法满足个人和企业的需求。据统计,全球每年有超过2亿人面临职业转型困境,而企业也因此遭…...
边缘计算网关提升水产养殖尾水处理的远程运维效率
一、项目背景 随着水产养殖行业的快速发展,养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下,而且难以实现精准监控和管理。为了提升尾水处理的效果和效率,同时降低人力成本,某大型水产养殖企业决定…...
篇章一 论坛系统——前置知识
目录 1.软件开发 1.1 软件的生命周期 1.2 面向对象 1.3 CS、BS架构 1.CS架构编辑 2.BS架构 1.4 软件需求 1.需求分类 2.需求获取 1.5 需求分析 1. 工作内容 1.6 面向对象分析 1.OOA的任务 2.统一建模语言UML 3. 用例模型 3.1 用例图的元素 3.2 建立用例模型 …...
