设计模式学习2
代理模式:Proxy
- 动机
“增加一层间接层”是软件系统中对许多复杂问题的一种常见解决方案。在面向对象系统中,直接食用某些对象会带来很多问题,作为间接层的proxy对象便是解决这一问题的常见手段。
2.伪代码:
class ISubject{
public:virtual void process();
};//Proxy的设计
class SubjectProxy: public ISubject{public:virtual void process(){//对RealSubject的一种间接访问//....}
};class ClientApp{ISubject* subject;public:ClientApp(){subject=new SubjectProxy();}void DoTask(){//...subject->process();//....}
};
3.理解:
copy on write就是这个思想。看类图以及代码简单,但是它真正的实现可能会很复杂。
4.类图:

适配器:Adapter
- 动机
需要将一些现存的对象放在新的环境中应用,但是新环境要求的接口是这些现存对象所不能满足的。如何应对这种迁移的变化?如何既能利用现存对象的良好实现,同时又能满足新的应用环境的要求接口?
2.伪代码:
//目标接口(新接口)
class ITarget{
public:virtual void process()=0;
};//遗留接口(老接口)
class IAdaptee{
public:virtual void foo(int data)=0;virtual int bar()=0;
};//遗留类型
class OldClass: public IAdaptee{//....
};//对象适配器
class Adapter: public ITarget{ //继承
protected:IAdaptee* pAdaptee;//组合public:Adapter(IAdaptee* pAdaptee){this->pAdaptee=pAdaptee;}virtual void process(){int data=pAdaptee->bar();pAdaptee->foo(data);}
};//类适配器
class Adapter: public ITarget,protected OldClass{ //多继承
}int main(){IAdaptee* pAdaptee=new OldClass();ITarget* pTarget=new Adapter(pAdaptee);pTarget->process();}class stack{deqeue container;};class queue{deqeue container;};
3.类图:

中介者模式:Mediator
- 动机
会出现多个对象互相交互的情况,对象之间通常会维持一种复杂的引用关系,如果遇到一些需求的更改,这种直接的引用关系将会面临不断变化。

2.伪代码:
与facade相同,思想,无代码
3.理解:
Colleague和Mediator两个类之间相互依赖,Colleague之间不相互依赖,但是会通过Mediator间接依赖。把直接依赖关系变为间接依赖关系。facade用于解耦内部与外部之间的关系,中介者相当于解耦facade内部之间的关系。
4.类图:

状态变化
在组件变化构建过程中,某些对象的状态经常面临变化,如何对这些变化进行有效的管理?同时又维持高层模块的稳定?
状态模式:State
- 动机
某些对象的状态如果改变,其行为也会随之改变。如何在运行时根据对象的状态来透明的更改对象的行为?而不会为对象操作和状态转变之间引入紧耦合?
2.伪代码:
class NetworkState{public:NetworkState* pNext;virtual void Operation1()=0;virtual void Operation2()=0;virtual void Operation3()=0;virtual ~NetworkState(){}
};class OpenState :public NetworkState{static NetworkState* m_instance;
public:static NetworkState* getInstance(){if (m_instance == nullptr) {m_instance = new OpenState();}return m_instance;}void Operation1(){//**********pNext = CloseState::getInstance();}void Operation2(){//..........pNext = ConnectState::getInstance();}void Operation3(){//$$$$$$$$$$pNext = OpenState::getInstance();}};class CloseState:public NetworkState{ }
//...class NetworkProcessor{NetworkState* pState;public:NetworkProcessor(NetworkState* pState){this->pState = pState;}void Operation1(){//...pState->Operation1();pState = pState->pNext;//...}void Operation2(){//...pState->Operation2();pState = pState->pNext;//...}void Operation3(){//...pState->Operation3();pState = pState->pNext;//...}};

备忘录模式:Memento
- 动机
某些对象的状态在转化过程中,可能有某种需要,要求程序能够回溯到对象之前处于某个点时的状态。如何在不破坏封装性的前提下实现这个任务呢?
2.伪代码:
class Memento
{string state;//..
public:Memento(const string & s) : state(s) {}string getState() const { return state; }void setState(const string & s) { state = s; }
};class Originator
{string state;//....
public:Originator() {}Memento createMomento() {Memento m(state);return m;}void setMomento(const Memento & m) {state = m.getState();}
};int main()
{Originator orginator;//捕获对象状态,存储到备忘录Memento mem = orginator.createMomento();//... 改变orginator状态//从备忘录中恢复orginator.setMomento(mem);
}
3.理解:
备忘录就是存储一个类的状态快照,在需要的时候设置为备忘录中的状态。核心是隐藏信息。这个模式有些过时。其实就是对象序列化。
4.类图:

数据结构
一些组件在内部具有特定的数据结构,如果让客户程序依赖于这些特定的数据结构,将破坏组件的复用性。这个时候,将这些数据结构封装在内部,对外提供统一的接口,来实现与特定的数据结构无关的访问。
组合模式:Composite
- 动机
如何将客户代码与复杂的对象容器结构解耦?让对象容器自己实现自身的复杂结构,从而使得客户代码就像处理简单对象一样来处理复杂的对象容器?
2.伪代码:
#include <iostream>
#include <list>
#include <string>
#include <algorithm>using namespace std;class Component
{
public:virtual void process() = 0;virtual ~Component(){}
};//树节点
class Composite : public Component{string name;list<Component*> elements;
public:Composite(const string & s) : name(s) {}void add(Component* element) {elements.push_back(element);}void remove(Component* element){elements.remove(element);}void process(){//1. process current node//2. process leaf nodesfor (auto &e : elements)e->process(); //多态调用}
};//叶子节点
class Leaf : public Component{string name;
public:Leaf(string s) : name(s) {}void process(){//process current node}
};void Invoke(Component & c){//...c.process();//...
}int main()
{Composite root("root");Composite treeNode1("treeNode1");Composite treeNode2("treeNode2");Composite treeNode3("treeNode3");Composite treeNode4("treeNode4");Leaf leaf1("left1");Leaf leaf2("left2");root.add(&treeNode1);treeNode1.add(&treeNode2);treeNode2.add(&leaf1);root.add(&treeNode3);treeNode3.add(&treeNode4);treeNode4.add(&leaf2);process(root);process(leaf2);process(treeNode3);}
3.理解:
对象组合成树形结构。和装饰器有点像,不仅has-a,而且is-a。将一对多的关系替换成一对一的关系。
4.类图:

迭代器:Iterator
- 动机
提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。
2.伪代码:
template<typename T>
class Iterator
{
public:virtual void first() = 0;virtual void next() = 0;virtual bool isDone() const = 0;virtual T& current() = 0;
};template<typename T>
class MyCollection{public:Iterator<T> GetIterator(){//...}};template<typename T>
class CollectionIterator : public Iterator<T>{MyCollection<T> mc;
public:CollectionIterator(const MyCollection<T> & c): mc(c){ }void first() override {}void next() override {}bool isDone() const override{}T& current() override{}
};void MyAlgorithm()
{MyCollection<int> mc;Iterator<int> iter= mc.GetIterator();for (iter.first(); !iter.isDone(); iter.next()){cout << iter.current() << endl;}}
3.理解:
对C++来说,面向对象的迭代器已经过时了。STL中的迭代器是泛型编程思想。运行时绑定是没有编译时绑定效率高的。
4.类图:

职责链模式:Chain Of Responsibility
- 动机
一个请求可能有多个接收者,但是真正的接受者,也就是去处理这个请求的只有一个。这时,请求发送者与接受者的耦合可能出现变化脆弱的情况。
2.伪代码:
#include <iostream>
#include <string>using namespace std;enum class RequestType
{REQ_HANDLER1,REQ_HANDLER2,REQ_HANDLER3
};class Reqest
{string description;RequestType reqType;
public:Reqest(const string & desc, RequestType type) : description(desc), reqType(type) {}RequestType getReqType() const { return reqType; }const string& getDescription() const { return description; }
};class ChainHandler{ChainHandler *nextChain;void sendReqestToNextHandler(const Reqest & req){if (nextChain != nullptr)nextChain->handle(req);}
protected:virtual bool canHandleRequest(const Reqest & req) = 0;virtual void processRequest(const Reqest & req) = 0;
public:ChainHandler() { nextChain = nullptr; }void setNextChain(ChainHandler *next) { nextChain = next; }void handle(const Reqest & req){if (canHandleRequest(req))processRequest(req);elsesendReqestToNextHandler(req);}
};class Handler1 : public ChainHandler{
protected:bool canHandleRequest(const Reqest & req) override{return req.getReqType() == RequestType::REQ_HANDLER1;}void processRequest(const Reqest & req) override{cout << "Handler1 is handle reqest: " << req.getDescription() << endl;}
};class Handler2 : public ChainHandler{
protected:bool canHandleRequest(const Reqest & req) override{return req.getReqType() == RequestType::REQ_HANDLER2;}void processRequest(const Reqest & req) override{cout << "Handler2 is handle reqest: " << req.getDescription() << endl;}
};class Handler3 : public ChainHandler{
protected:bool canHandleRequest(const Reqest & req) override{return req.getReqType() == RequestType::REQ_HANDLER3;}void processRequest(const Reqest & req) override{cout << "Handler3 is handle reqest: " << req.getDescription() << endl;}
};int main(){Handler1 h1;Handler2 h2;Handler3 h3;h1.setNextChain(&h2);h2.setNextChain(&h3);Reqest req("process task ... ", RequestType::REQ_HANDLER3);h1.handle(req);return 0;
}
3.理解:
应用的不多。使得多个接收者都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理请求为止。
4.类图:

行为变化
在组件的构建过程中,组件行为的变化经常导致组件本身的剧烈变化。下面的模式将组件本身和组件的行为进行解耦
命令模式:Command
- 动机
如何将行为请求者和行为实现者解耦?
2.伪代码:
#include <iostream>
#include <vector>
#include <string>
using namespace std;class Command
{
public:virtual void execute() = 0;
};class ConcreteCommand1 : public Command
{string arg;
public:ConcreteCommand1(const string & a) : arg(a) {}void execute() override{cout<< "#1 process..."<<arg<<endl;}
};class ConcreteCommand2 : public Command
{string arg;
public:ConcreteCommand2(const string & a) : arg(a) {}void execute() override{cout<< "#2 process..."<<arg<<endl;}
};class MacroCommand : public Command
{vector<Command*> commands;
public:void addCommand(Command *c) { commands.push_back(c); }void execute() override{for (auto &c : commands){c->execute();}}
};int main()
{ConcreteCommand1 command1(receiver, "Arg ###");ConcreteCommand2 command2(receiver, "Arg $$$");MacroCommand macro;macro.addCommand(&command1);macro.addCommand(&command2);macro.execute();}
3.理解:
有点和仿函数思想类似。将一个请求封装成一个对象,从而使你可用不同的请求对客户进行参数化。
4.类图:

访问器模式:Visitor
- 动机
在软件构件的过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为,如果直接在基类中作出修改,将会给子类带来繁重的变更负担,甚至破坏原有设计。
2.伪代码:
#include <iostream>
using namespace std;class Visitor;class Element
{
public:virtual void accept(Visitor& visitor) = 0; //第一次多态辨析virtual ~Element(){}
};class ElementA : public Element
{
public:void accept(Visitor &visitor) override {visitor.visitElementA(*this);}};class ElementB : public Element
{
public:void accept(Visitor &visitor) override {visitor.visitElementB(*this); //第二次多态辨析}};class Visitor{
public:virtual void visitElementA(ElementA& element) = 0;virtual void visitElementB(ElementB& element) = 0;virtual ~Visitor(){}
};//==================================//扩展1
class Visitor1 : public Visitor{
public:void visitElementA(ElementA& element) override{cout << "Visitor1 is processing ElementA" << endl;}void visitElementB(ElementB& element) override{cout << "Visitor1 is processing ElementB" << endl;}
};//扩展2
class Visitor2 : public Visitor{
public:void visitElementA(ElementA& element) override{cout << "Visitor2 is processing ElementA" << endl;}void visitElementB(ElementB& element) override{cout << "Visitor2 is processing ElementB" << endl;}
};int main()
{Visitor2 visitor;ElementB elementB;elementB.accept(visitor);// double dispatchElementA elementA;elementA.accept(visitor);return 0;
}
3.理解:
Visitor中要求具体的Element稳定,这个条件通常很难保证,这是这个模式的重大缺点。accept方法表示接受一个visitor,这个visitor能够为该类增添新的方法。一般不用,因为前提条件很苛刻。
Visitor通过双重分发来实现不更改Element层次结构的前提下,在运行时透明的为类层次结构上的各个类添加新的操作。
适用于:Element类层次结构稳定,而其中的操作确实频繁改动的。(设计思想:有动的,有不动的)
4.类图:

领域规则
某些领域,变化虽然频繁,但是可以抽象为某种规则。要给出该领域下的对于变化的一般性解决方案。
解析器模式:Interpreter
- 动机
如果特定领域的某一问题比较复杂,类似的结构不断出现,如果使用普通的编程方式来实现将会面临非常频繁的变化。在这种情况下,将特定领域的问题表达为某种语法规则下的句子,然后构建一个解释器来解释这样的句子,从而达到解决问题的目的。
2.伪代码:
#include <iostream>
#include <map>
#include <stack>using namespace std;class Expression {
public:virtual int interpreter(map<char, int> var)=0;virtual ~Expression(){}
};//变量表达式
class VarExpression: public Expression {char key;public:VarExpression(const char& key){this->key = key;}int interpreter(map<char, int> var) override {return var[key];}};//符号表达式
class SymbolExpression : public Expression {// 运算符左右两个参数
protected:Expression* left;Expression* right;public:SymbolExpression( Expression* left, Expression* right):left(left),right(right){}};//加法运算
class AddExpression : public SymbolExpression {public:AddExpression(Expression* left, Expression* right):SymbolExpression(left,right){}int interpreter(map<char, int> var) override {return left->interpreter(var) + right->interpreter(var);}};//减法运算
class SubExpression : public SymbolExpression {public:SubExpression(Expression* left, Expression* right):SymbolExpression(left,right){}int interpreter(map<char, int> var) override {return left->interpreter(var) - right->interpreter(var);}};Expression* analyse(string expStr) {stack<Expression*> expStack;Expression* left = nullptr;Expression* right = nullptr;for(int i=0; i<expStr.size(); i++){switch(expStr[i]){case '+':// 加法运算left = expStack.top();right = new VarExpression(expStr[++i]);expStack.push(new AddExpression(left, right));break;case '-':// 减法运算left = expStack.top();right = new VarExpression(expStr[++i]);expStack.push(new SubExpression(left, right));break;default:// 变量表达式expStack.push(new VarExpression(expStr[i]));}}Expression* expression = expStack.top();return expression;
}void release(Expression* expression){//释放表达式树的节点内存...
}int main(int argc, const char * argv[]) {string expStr = "a+b-c+d-e";map<char, int> var;var.insert(make_pair('a',5));var.insert(make_pair('b',2));var.insert(make_pair('c',1));var.insert(make_pair('d',6));var.insert(make_pair('e',10));Expression* expression= analyse(expStr);int result=expression->interpreter(var);cout<<result<<endl;release(expression);return 0;
}
3.理解:
可以理解为四则运算的运算树。使用场景为:业务规则频繁变化,且类似的结构重复出现,并且容易(简单简单,小而简单的问题)抽象为有规则的问题。
4.类图:

总结
- 模版方法:用于制定一套模板,别人来用的时候按照模板实现
- 策略模式:方便新增策略,只需新增一个子类
- 观察者模式:方便通知消息
- 装饰模式:方便拓展功能
- 桥模式:用于桥接两个向不同纬度变化的类,这个桥,就是一个类中组合另外一个类
- 工厂方法:创建对象解耦合
- 抽象工厂:工厂的工厂,要生产一系列的产品,这一系列产品需要配套
- 原型方法:有clone方法来完成对象创建
- 构建者:分步骤构建一个对象,将表示和构建分离
- 单件模式:保证在内存中一个类只存在一个实例
- 享元模式:运用共享技术有效地支持大量细粒度的对象,大量大量!线程池
- 门面模式:不管facade内部怎么变化,对于用户来说,接口都是一样的
- 代理模式:就像VPN一样,间接控制。
- 适配器:改变原始类接口,适配新类。比如STL中的stack
- 中介者模式:把直接依赖关系变为间接依赖关系
- 状态模式:将策略模式的策略改为状态
- 备忘录模式:存储一个类的状态快照,在需要的时候设置为备忘录中的状态
- 组合模式:对象组合成树形结构。将一对多的关系替换成一对一的关系
- 迭代器:STL中的迭代器思想
- 职责链:处理请求的对象连成一条链
- 命令模式:将行为抽象为对象,有点和仿函数类似
- 访问器模式:使用双重分发的机制,透明的添加新的操作
- 解释器模式:四则运算树
参考文章:侯捷C++八部曲笔记(三、设计模式)_侯捷c++设计模式-CSDN博客
相关文章:
设计模式学习2
代理模式:Proxy 动机 “增加一层间接层”是软件系统中对许多复杂问题的一种常见解决方案。在面向对象系统中,直接食用某些对象会带来很多问题,作为间接层的proxy对象便是解决这一问题的常见手段。 2.伪代码: class ISubject{ pu…...
Rust:如何判断位置结构的JSON串的成员的数据类型
如何判断位置结构的JSON串的成员的数据类型,给一个Rust的例子,其中包含对数组的判断? 在Rust中,你可以使用serde_json库来处理JSON数据,并通过serde_json::Value类型的方法来判断JSON串中成员的数据类型。以下是一个示…...
Kafka(五)生产者
目录 Kafka生产者1 配置生产者bootstrap.serverskey.serializervalue.serializerclient.id""acksallbuffer.memory33554432(32MB)compression.typenonebatch.size16384(16KB)max.in.flight.requests.per.connection5max.request.size1048576(1MB)receive.buffer.byte…...
【Leetcode】242.有效的字母异位词
一、题目 1、题目描述 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。 示例1: 输入: s = "anagram", t = "nagaram" 输出: true示例2: 输入: …...
【数据库原理】(16)关系数据理论的函数依赖
一.函数依赖的概念 函数依赖是关系数据库中核心的概念,它指的是在属性集之间存在的一种特定的关系。这种关系表明,一个属性集的值可以唯一确定另一个属性集的值。 属性子集:在关系模式中,X和Y可以是单个属性,也可以是…...
脆弱的SSL加密算法漏洞原理以及修复方法
漏洞名称:弱加密算法、脆弱的加密算法、脆弱的SSL加密算法、openssl的FREAK Attack漏洞 漏洞描述:脆弱的SSL加密算法,是一种常见的漏洞,且至今仍有大量软件支持低强度的加密协议,包括部分版本的openssl。其实…...
SVN迁移至GitLab,并附带历史提交记录(二)
与《SVN迁移至GitLab,并附带历史提交记录》用的 git svn clone不同,本文使用svn2git来迁移项目代码。 一、准备工作 安装Git环境,配置本地git账户信息: git config --global user.name "XXX" git config --global us…...
如何创建容器搭建节点
1.注册Discord账号 https://discord.com/这是登录网址: https://discord.com/ 2.点击startnow注册,用discord注册或者邮箱注册都可,然后登录tickhosting Tick Hosting这是登录网址:Tick Hosting 3.创建servers 4.点击你创建的servers,按照图中步骤进行...
微众区块链观察节点的架构和原理 | 科普时间
践行区块链公共精神,实现更好的公众开放与监督!2023年12月,微众区块链观察节点正式面向公众开放接入功能。从开放日起,陆续有多个观察节点在各地运行,同步区块链数据,运行区块链浏览器观察检视数据…...
React Admin 前端脚手架之ant-design-pro
文章目录 一、React Admin 前端脚手架选型二、React Admin 前端脚手架之ant-design-pro三、ant-design-pro使用步骤四、调试主题五、常用总结(持续更新)EditableProTable组件 常用组件EditableProTable组件 编辑某行后,保存时候触发发送请求EditableProTable组件,添加记录提…...
向爬虫而生---Redis 基石篇1 <拓展str>
前言: 本来是基于scrapy-redis进行讲解的,需要拓展一下redis; 包含用法,设计,高并发,阻塞等; 要应用到爬虫开发中,这些基础理论我觉得还是有必要了解一下; 所以,新开一栏! 把redis这个环节系统补上,再转回去scrapy-redis才好深入; 正文: Redis是一种内存数据库,…...
【野火i.MX6ULL开发板】利用microUSB线烧入Debian镜像
0、前言 烧入Debian镜像有两种方式:SD卡、USB SD卡:需要SD卡(不是所有型号都可以,建议去了解了解)、SD卡读卡器 USB:需要microUSB线 由于SD卡的网上资料很多了,又因为所需硬件(SD卡…...
“我在大A炒自己”
嘻嘻嘻,大伙儿好像还挺喜欢我闲聊,今天太忙,没得空精进技术,那咱还是接着闲聊吧😂😂 看到标题点进来的各位大A真爱粉,请先收下我的崇高敬意!!别误会,标题说的…...
js 颜色转换,RGB颜色转换为16进制,16进制颜色转为RGB格式
颜色转换,RGB颜色转换为16进制,16进制颜色转为RGB格式,可以自己设置透明度。 //十六进制颜色值的正则表达式 var reg /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/; /*RGB颜色转换为16进制*/ String.prototype.colorHex function () {var that this;if (/^…...
uniapp中用户登录数据的存储方法探究
Hello大家好!我是咕噜铁蛋!作为一个博主,我们经常需要在应用程序中实现用户登录功能,并且需要将用户的登录数据进行存储,以便在多次使用应用程序时能够方便地获取用户信息。铁蛋通过科技手段帮大家收集整理了些知识&am…...
引导过程与服务控制
文章目录 一、Linux操作系统引导过程1、开机启动的完整过程1.1 开机自检(BIOS)1.2 MBR引导1.3 GRUB菜单1.4 加载内核(kernel)1.5 init进程初始化 2、系统初始化进程2.1 init进程2.2 systemdinit与systemd区别 3、Systemd单元类型4…...
《矩阵分析》笔记
来源:【《矩阵分析》期末速成 主讲人:苑长(5小时冲上90)】https://www.bilibili.com/video/BV1A24y1p76q?vd_sourcec4e1c57e5b6ca4824f87e74170ffa64d 这学期考矩阵论,使用教材是《矩阵论简明教程》,因为没…...
『App自动化测试之Appium应用篇』| Appium常用API及操作
『App自动化测试之Appium应用篇』| Appium常用API及操作 1 press_keycode1.1 键盘操作1.2 关于KeyCode1.3 press_keycode源码1.4 电话键相关1.5 控制键相关1.6 基本按键相关1.7 组合键相关1.8 符号键相关1.9 使用举例 2 swip方法2.1 swip说明2.2 swip使用方法2.3 使用示例 3 sc…...
VSCode搭建 .netcore 开发环境
一、MacOS 笔者笔记本电脑上安装的是macOS High Sierra(10.13),想要尝试一下新版本的.netcore,之前系统是10.12时,.netcore 3.1刚出来时安装过3.1版本,很久没更新了,最近.net8出来了,想试一下,…...
python 写自动点击爬取数据
今天来点不一样的!哥们 提示: 这里只是用于自己学习的 ,请勿用违法地方 效果图 会进行点击下一页 进行抓取 需要其他操作也可以自己写 文章目录 今天来点不一样的!哥们前言一、上代码?总结 前言 爬虫是指通过编程自动…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
ubuntu清理垃圾
windows和ubuntu 双系统,ubuntu 150GB,开发用,基本不装太多软件。但是磁盘基本用完。 1、查看home目录 sudo du -h -d 1 $HOME | grep -v K 上面的命令查看$HOME一级目录大小,发现 .cache 有26GB,.local 有几个GB&am…...
生成对抗网络(GAN)损失函数解读
GAN损失函数的形式: 以下是对每个部分的解读: 1. , :这个部分表示生成器(Generator)G的目标是最小化损失函数。 :判别器(Discriminator)D的目标是最大化损失函数。 GAN的训…...
Ubuntu 可执行程序自启动方法
使用 autostart(适用于桌面环境) 适用于 GNOME/KDE 桌面环境(如 Ubuntu 图形界面) 1. 创建 .desktop 文件 sudo vi ~/.config/autostart/my_laser.desktop[Desktop Entry] TypeApplication NameMy Laser Program Execbash -c &…...
