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

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++ 设计模式 的课本范例(下)

&#xff08;19&#xff09; 桥接模式 Bridge&#xff0c;不是采用类继承&#xff0c;而是采用类组合&#xff0c;一个类的数据成员是类对象&#xff0c;来扩展类的功能。源码如下&#xff1a; class OS // 操作系统负责绘图 { public:virtual ~OS() {}virtual void draw(cha…...

结合数据索引结构看SQL的真实执行过程

引言 关于数据库设计与优化的前几篇文章中&#xff0c;我们提到了数据库设计优化应该遵守的指导原则、数据库底层的索引组织结构、数据库的核心功能组件以及SQL的解析、编译等。这些其实都是在为SQL的优化、执行的理解打基础。 今天这篇文章&#xff0c;我们以MySQL中InnoDB存…...

spark shuffle——shuffle管理

ShuffleManager shuffle系统的入口。ShuffleManager在driver和executor中的sparkEnv中创建。在driver中注册shuffle&#xff0c;在executor中读取和写入数据。 registerShuffle&#xff1a;注册shuffle&#xff0c;返回shuffleHandle unregisterShuffle&#xff1a;移除shuff…...

HTMLCSS(入门)

HTML <html> <head><title>第一个页面</title></head><body>键盘敲烂&#xff0c;工资过万</body> </html> <!DOCTYPE>文档类型声明&#xff0c;告诉浏览器使用哪种HTML版本显示网页 <!DOCTYPE html>当前页面采取…...

富格林:曝光可信策略制止亏损

富格林指出&#xff0c;相信大家都对黄金投资的价值空间有目共睹&#xff0c;现如今黄金市场波动频繁&#xff0c;因此不少投资者也开始加入该市场试图赢得额外的财富。但作为新手投资者贸贸然地进场操作&#xff0c;亏损的几率是很大的&#xff0c;因此要学会掌握正规平台曝光…...

Android --- Service

出自于此&#xff0c;写得很清楚。关于Android Service真正的完全详解&#xff0c;你需要知道的一切_android service-CSDN博客 出自【zejian的博客】 什么是Service? Service(服务)是一个一种可以在后台执行长时间运行操作而没有用户界面的应用组件。 服务可由其他应用组件…...

Vue3从入门到精通(三)

vue3插槽Slots 在 Vue3 中&#xff0c;插槽&#xff08;Slots&#xff09;的使用方式与 Vue2 中基本相同&#xff0c;但有一些细微的差异。以下是在 Vue3 中使用插槽的示例&#xff1a; // ChildComponent.vue <template><div><h2>Child Component</h2&…...

【FreeRTOS】同步与互斥通信-有缺陷的互斥案例

目录 同步与互斥通信同步与互斥的概念同步与互斥并不简单缺陷分析汇编指令优化过程 - 关闭中断时间轴分析 思考时刻 参考《FreeRTOS入门与工程实践(基于DshanMCU-103).pdf》 同步与互斥通信 同步与互斥的概念 一句话理解同步与互斥&#xff1a;我等你用完厕所&#xff0c;我再…...

Docker 安装 Python

Docker 安装 Python 在当今的软件开发领域,Docker 已成为一项关键技术,它允许开发人员将应用程序及其依赖环境打包到一个可移植的容器中。Python,作为一种广泛使用的高级编程语言,经常被部署在 Docker 容器中。本文将详细介绍如何在 Docker 中安装 Python,以及如何配置环…...

外泌体相关基因肝癌临床模型预测——2-3分纯生信文章复现——4.预后相关外泌体基因确定单因素cox回归(2)

内容如下&#xff1a; 1.外泌体和肝癌TCGA数据下载 2.数据格式整理 3.差异表达基因筛选 4.预后相关外泌体基因确定 5.拷贝数变异及突变图谱 6.外泌体基因功能注释 7.LASSO回归筛选外泌体预后模型 8.预后模型验证 9.预后模型鲁棒性分析 10.独立预后因素分析及与临床的…...

C++: Map数组的遍历

在C中&#xff0c;map是一个关联容器&#xff0c;它存储的元素是键值对&#xff08;key-value pairs&#xff09;&#xff0c;其中每个键都是唯一的&#xff0c;并且自动根据键来排序。遍历map的方式有几种&#xff0c;但最常用的两种是使用迭代器&#xff08;iterator&#xf…...

【Windows】Bootstrap Studio(网页设计)软件介绍及安装步骤

软件介绍 Bootstrap Studio 是一款专为前端开发者设计的强大工具&#xff0c;主要用于快速创建现代化的响应式网页和网站。以下是它的主要特点和功能&#xff1a; 直观的界面设计 Bootstrap Studio 提供了直观的用户界面&#xff0c;使用户能够轻松拖放元素来构建网页。界面…...

二维舵机颜色追踪,使用树莓派+opencv+usb摄像头+两个舵机实现颜色追踪,采用pid调控

效果演示 二维云台颜色追踪 使用树莓派opencvusb摄像头两个舵机实现颜色追踪&#xff0c;采用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 中的一个标准库函数&#xff0c;用于内存拷贝操作。它的原型通常定义在 <cstring> 头文件中&#xff0c;其作用是将一块内存中的数据复制到另一块内存中。 函数原型&#xff1a;void *memcpy(void *dest, const void…...

新手入门:无服务器函数和FaaS简介

无服务器&#xff08;Serverless&#xff09;架构的价值在于其成本效益、弹性和扩展性、简化的开发和部署流程、高可用性和可靠性以及使开发者能够专注于业务逻辑。通过自动化资源调配和按需计费&#xff0c;无服务器架构能够降低成本并适应流量变化&#xff0c;同时简化开发流…...

基于Transformer的端到端的目标检测 | 读论文

本文正在参加 人工智能创作者扶持计划 提及到计算机视觉的目标检测&#xff0c;我们一般会最先想到卷积神经网络&#xff08;CNN&#xff09;&#xff0c;因为这算是目标检测领域的开山之作了&#xff0c;在很长的一段时间里人们都折服于卷积神经网络在图像处理领域的优势&…...

6.8应用进程跨网络通信

《计算机网络》第7版&#xff0c;谢希仁 理解socket通信...

redis布隆过滤器原理及应用场景

目录 原理 应用场景 优点 缺点 布隆过滤器&#xff08;Bloom Filter&#xff09;是一种空间效率很高的随机数据结构&#xff0c;它利用位数组和哈希函数来判断一个元素是否存在于集合中。 原理 数据结构&#xff1a; 位数组&#xff1a;一个由0和1组成的数组&#xff0c;初始…...

vue+openlayers之几何图形交互绘制基础与实践

文章目录 1.实现效果2.实现步骤3.示例页面代码3.基本几何图形绘制的关键代码 1.实现效果 绘制点、线、多边形、圆、正方形、长方形 2.实现步骤 引用openlayers开发库。加载天地图wmts瓦片地图。在页面上添加几何图形绘制的功能按钮&#xff0c;使用下拉列表&#xff08;sel…...

「多模态大模型」解读 | 突破单一文本模态局限

编者按&#xff1a;理想状况下&#xff0c;世界上的万事万物都能以文字的形式呈现&#xff0c;如此一来&#xff0c;我们似乎仅凭大语言模型&#xff08;LLMs&#xff09;就能完成所有任务。然而&#xff0c;理想很丰满&#xff0c;现实很骨感——数据形态远不止文字一种&#…...

Redis深度解析:核心数据类型与键操作全攻略

文章目录 前言redis数据类型string1. 设置单个字符串数据2.设置多个字符串类型的数据3.字符串拼接值4.根据键获取字符串的值5.根据多个键获取多个值6.自增自减7.获取字符串的长度8.比特流操作key操作a.查找键b.设置键值的过期时间c.查看键的有效期d.设置key的有效期e.判断键是否…...

C语言 指针和数组——指针的算术运算

目录 指针的算术运算 指针加上一个整数 指针减去一个整数 指针相减 指针的关系比较运算 小结 指针的算术运算 指针加上一个整数 指针减去一个整数 指针相减 指针的关系比较运算 小结  指针变量 – 指针类型的变量&#xff0c;保存地址型数据  指针变量与其他类型…...

[C++][CMake][CMake基础]详细讲解

目录 1.CMake简介2.大小写&#xff1f;3.注释1.注释行2.注释块 4.日志 1.CMake简介 CMake是一个项目构建工具&#xff0c;并且是跨平台的 问题 – 解决 如果自己动手写Makefile&#xff0c;会发现&#xff0c;Makefile通常依赖于当前的编译平台&#xff0c;而且编写Makefile的…...

CCD技术指标

CCD尺寸&#xff0c;即摄象机靶面。原多为1/2英寸&#xff0c;现在1/3英寸的已普及化&#xff0c;1/4英寸和1/5英寸也已商品化。CCD像素&#xff0c;是决定了显示图像的清晰程度&#xff0c;。CCD是由面阵感光元素组成&#xff0c;每一个元素称为像素&#xff0c;像素越多&…...

SpringBoot系列——使用Spring Cache和Redis实现查询数据缓存

文章目录 1. 前言2. 缓存2.1 什么是缓存2.2 使用缓存的好处2.3 缓存的成本2.4 Spring Cache和Redis的优点 3. Spring Cache基础知识3.1 Spring Cache的核心概念3.2 Spring Cache的注解3.2.1 SpEL表达式3.2.2 Cacheable3.2.3 CachePut3.2.4 CacheEvict 4. 实现查询数据缓存4.1 准…...

【算法】(C语言):冒泡排序、选择排序、插入排序

冒泡排序 从第一个数据开始到第n-1个数据&#xff0c;依次和后面一个数据两两比较&#xff0c;数值小的在前。最终&#xff0c;最后一个数据&#xff08;第n个数据&#xff09;为最大值。从第一个数据开始到第n-2个数据&#xff0c;依次和后面一个数据两两比较&#xff0c;数值…...

iOS项目怎样进行二进制重排

什么是二进制重排 &#xff1f; 在iOS项目中&#xff0c;二进制重排&#xff08;Binary Reordering 或者 Binary Rearrangement&#xff09;是一种优化技术&#xff0c;主要目的是通过重新组织应用程序的二进制文件中的代码和数据段&#xff0c;来提高应用程序的性能&#xff…...

CentOS中使用SSH远程登录

CentOS中使用SSH远程登录 准备工作SSH概述SSH服务的安装与启动建立SSH连接SSH配置文件修改SSH默认端口SSH文件传输 准备工作 两台安装CentOS系统的虚拟机 客户机&#xff08;192.168.239.128&#xff09; 服务器&#xff08;192.168.239.129&#xff09; SSH概述 Secure S…...

spring @Autowire注解作用

终于有人把Autowired注解讲清楚了&#xff0c;赞&#xff01;&#xff01;&#xff01;_autowired-CSDN博客...

密码学原理精解【5】

这里写目录标题 移位密码概述代码 希尔密码( Z 256 Z_{256} Z256​)待加密长度被3整除待加密长度不一定被3整除加解密文件 移位密码 概述 以 z 26 运算为例 , k 为密钥 加密&#xff1a; e k ( x ) ( x k ) m o d 26 解密&#xff1a; d k ( x ) ( x − k ) m o d 26 以z_{…...

Unity3D 资源管理YooAsset原理分析与详解

引言 Unity3D 是一款广泛应用于游戏开发、虚拟现实&#xff08;VR&#xff09;、增强现实&#xff08;AR&#xff09;等领域的强大游戏开发引擎。在开发过程中&#xff0c;资源管理是一项至关重要的任务&#xff0c;它直接影响到游戏的性能和用户体验。YooAsset 是一个基于 Un…...

npm install puppeteer 报错 npm ERR! PUPPETEER_DOWNLOAD_HOST is deprecated解决办法

npm install puppeteer 报错如下&#xff1a; npm ERR! PUPPETEER_DOWNLOAD_HOST is deprecated. Use PUPPETEER_DOWNLOAD_BASE_URL instead. npm ERR! Error: ERROR: Failed to set up Chrome v126.0.6478.126! Set "PUPPETEER_SKIP_DOWNLOAD" env variable to sk…...

浙大版PTA《Python 程序设计》题目集 参考答案

浙大版PTA《Python 程序设计》题目集 参考答案 本答案配套详解教程专栏&#xff0c;欢迎订阅&#xff1a; PTA浙大版《Python 程序设计》题目集 详解教程_少侠PSY的博客-CSDN博客 01第1章-1 从键盘输入两个数&#xff0c;求它们的和并输出 aint(input()) # 输入a的值 bint(…...

“拆分盘投资:机遇与风险并存

一、引言 随着互联网技术的日新月异&#xff0c;金融投资领域迎来了前所未有的变革&#xff0c;其中拆分盘作为一种新兴的投资模式&#xff0c;正逐渐进入公众的视野。其独特的价值增长逻辑和创新的投资机制&#xff0c;为投资者开辟了新的财富增值渠道。本文旨在深入探讨拆分…...

Java面试题系列 - 第2天

题目&#xff1a;Java中的线程池模型及其配置策略 背景说明&#xff1a;在Java多线程编程中&#xff0c;线程池是一种高效的线程复用机制&#xff0c;能够有效管理和控制线程的创建与销毁&#xff0c;避免频繁创建和销毁线程带来的性能开销。理解和掌握线程池的配置策略对于优…...

AGI|Transformer自注意力机制超全扫盲攻略,建议收藏!

一、前言 2017年&#xff0c;谷歌团队推出一篇神经网络的论文&#xff0c;首次提出将“自注意力”机制引入深度学习中&#xff0c;这一机制可以根据输入数据各部分重要性的不同而分配不同的权重。当ChatGPT震惊世人时&#xff0c;Transformer也随之进入大众视野。一夜之间&…...

QT+OpenCV在Android上实现人脸实时检测与目标检测

一、功能介绍 在当今的移动应用领域&#xff0c;随着技术的飞速发展和智能设备的普及&#xff0c;将先进的计算机视觉技术集成到移动平台&#xff0c;特别是Android系统中&#xff0c;已成为提升用户体验、拓展应用功能的关键。其中&#xff0c;目标检测与人脸识别作为计算机视…...

常见网络攻击方式及防御方法

1. DDOS攻击&#xff08;分布式拒绝服务攻击&#xff09; 概念&#xff1a;借助于C/S&#xff08;客户端/服务器&#xff09;技术&#xff0c;将多个计算机联合起来作为攻击平台&#xff0c;对一个或多个目标发动DDOS攻击&#xff0c;从而成倍地提高拒绝服务攻击的威力。防护方…...

使用 ESP32 实现无线对讲机功能涉及音频采集、音频传输以及音频播放等多个方面。实现无线对讲机功能的基本步骤和示例代码。

硬件准备 两个 ESP32 开发板两个 MAX9814 麦克风模块&#xff08;或其他兼容的模拟麦克风模块&#xff09;两个 MAX98357A DAC 模块&#xff08;或其他兼容的音频放大器模块&#xff09;扬声器 接线 麦克风模块 -> ESP32 ADC 引脚ESP32 DAC 引脚 -> 音频放大器模块 -&…...

SpringBoot项目,配置文件pom.xml的结构解析

pom.xml 是 Maven 项目对象模型&#xff08;Project Object Model&#xff09;的配置文件&#xff0c;它定义了 Maven 项目的基本设置和构建过程。以下是 pom.xml 文件的基本结构和一些常见元素的解析&#xff1a; 项目声明 (<project>): <modelVersion>: 通常设置…...

教程:Spring Boot中集成Memcached的详细步骤

教程&#xff1a;Spring Boot中集成Memcached的详细步骤 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 在现代应用开发中&#xff0c;缓存是提升性能和扩展性…...

Websocket通信实战项目(图片互传应用)+PyQt界面+python异步编程(async) (上)服务器端python实现

Rqtz : 个人主页 ​​ 共享IT之美&#xff0c;共创机器未来 ​ Sharing the Beauty of IT and Creating the Future of Machines Together 目录 项目背景 ​编辑​专有名词介绍 服务器GUI展示 功能(位置见上图序号) 客户端GUI展示&#xff08;h5cssjs&#xf…...

实验一 MATLAB \ Python数字图像处理初步

一、实验目的&#xff1a; 1&#xff0e;熟悉及掌握在MATLAB\Python中能够处理哪些格式图像。 2&#xff0e;熟练掌握在MATLAB\Python中如何读取图像。 3&#xff0e;掌握如何利用MATLAB\Python来获取图像的大小、颜色、高度、宽度等等相关信息。 4&#xff0e;掌握如何在M…...

echarts柱状选中shadow阴影背景宽度设置

使用line&#xff0c;宽度增大到所需要的宽度&#xff0c;设置下颜色透明度就行 tooltip: {trigger: axis,//把阴影的层级往下降z:-15,axisPointer: {type: line,lineStyle: {color: rgba(150,150,150,0.3),width: 44,type: solid,},}, }, series: [{type: bar,barWidth:20,//…...

ArrayBuffer 对象常见的几个用途

ArrayBuffer 在 JavaScript 中的用途广泛&#xff0c;主要用于处理二进制数据。 ArrayBuffer 对象、 TypedArray 视图和 DataView 视图是 JavaScript 操作二进制数据的一个接口。本文介绍ArrayBuffer 对象的常见的一些用法。 1. 网络传输二进制数据 使用方法&#xff1a;通过 …...

STC89C52RC单片机设计的FM收音机+自动搜台+存储电台(程序+原理图+PCB)

资料下载地址&#xff1a;STC89C52RC单片机设计的FM收音机自动搜台存储电台&#xff08;程序原理图PCB) 1、实物图 2、部分程序 #include <reg52.h> #include "tea5767.h" #include "delay.h" #include "lcd1602.h" //K1:上一台 K2:下一…...

【若依】关闭当前标签页并跳转路由到其他页面

使用场景如&#xff1a;当在新增/编辑路由页面提交成功后&#xff0c;需要关闭当前页&#xff0c;并跳转回列表页。 实现代码&#xff1a; this.$store.dispatch("tagsView/delView", this.$route); //关闭当前页 this.$router.replace({ path: "/xxx/xxx"…...

防爆智能手机如何解决危险环境下通信难题?

在化工厂、石油行业、矿山等危险环境中&#xff0c;通信安全一直是难题。传统手机因不具备防爆功能&#xff0c;可能引发火花、爆炸等安全风险&#xff0c;让工作人员在关键时刻难以及时沟通。但如今&#xff0c;防爆智能手机的出现彻底改变了这一现状&#xff01; 安全通信&am…...

软件测试最全面试题及答案整理(2024最新版)

1、你的测试职业发展是什么? 测试经验越多&#xff0c;测试能力越高。所以我的职业发展是需要时间积累的&#xff0c;一步步向着高级测试工程师奔去。而且我也有初步的职业规划&#xff0c;前3年积累测试经验&#xff0c;按如何做好测试工程师的要点去要求自己&#xff0c;不断…...

11 - matlab m_map地学绘图工具基础函数 - 绘制航迹、椭圆、风向玫瑰图和特定的圆形区域的有关函数及其用法

11 - matlab m_map地学绘图工具基础函数 - 绘制航迹、椭圆、风向玫瑰图和特定的圆形区域的有关函数及其用法 0. 引言1. 关于m_track2. 关于m_range_ring3. 关于m_ellipse4. 关于m_windrose5. 结语 0. 引言 本篇介绍下m_map中绘制航迹图函数&#xff08;m_track&#xff09;、绘…...