C++设计模式笔记
设计模式
如何解决复杂性?
分解
核心思想:分而治之,将大问题分解为多个小问题,将复杂问题分解为多个简单的问题。
抽象
核心思想:从高层次角度讲,人们处理复杂性有一个通用的技术,及抽象。由于不能掌握全部的复杂对象,选择护士他的非本质细节,而去处理泛化和理想化的对象模型。
总结来说就是,复用最好的代码就是复用性高。
面向对象设计原则
对象的概念:
- 从语言实现层面来看,对象封装了代码和数据。
- 从规格层面讲,对象是一系列可被使用的公共接口。
- 从概念层面讲,对象时某种拥有责任的抽象。
设计原则
依赖倒置原则(DIP):
- 高层模块(稳定)不应该依赖于低层模块(变化)二者都应该依赖于抽象(稳定)。
- 抽象(稳定)不应该依赖于实现细节(变化),实现细节应该依赖于抽象(稳定)。
开放封闭原则(OCP):
- 对扩展开放,对更改封闭。
- 类模块应该是可扩展的,但是不可修改。
单一职责原则(SRP):
- 一个类应该仅有一个引起它变化的原则。
- 变化的方向隐含着类的责任。
Liskov替换原则(LSP):
- 子类必须能够替换他们的基类。
- 继承表达类型抽象
接口隔离原则(ISP):
- 不应该强迫客户程序依赖他们不用的方法。
- 接口应该小而完备。
优先使用对象组合,而不是类继承
- 类继承通常为“白箱复用”,对象组合通常为“黑箱复用”。
- 继承在某种程度上破坏了封装性,子类父类耦合度很高。
- 而对象组合则只要求被组合的对象具有良好定义的接口,耦合度低。
封装变化点:
- 使用封装来创建对象之间的分界层,让设计者可以在分界层的一侧进行修改,而不会对另一侧产生不良影响,从而实现层次间的松耦合。
针对接口与编码,而不是针对实现编程:产业强盛的标志
- 不将变量类型声明为某个特定的具体类,而是声明为某个接口
- 客户程序无需获知对象的具优类型,只需要知道对象所具有的接口。
- 减少系统中各部分的依赖关系从而实现“高内聚、松耦合’的类型设计方案。
GOF-23模式分类
从目的来看:
- 创建型模式:将对象的部分创建工作延迟到子类或者其他对象,从而应对需求变化为对象创建时具体类型实现引来的冲击。
- 结构型模式:通过类继承或者对象组合获得更灵活的结构,从而应对需求变化为对象的结构带来的冲击。
- 行为型模式:通过类继承或者对象组合来划分类与对象间的职责,从而应对需求变化为多个交互的对象带来的冲击。
从范围来看:
- 类模式处理类与子类的静态关系。
- 对象模式处理对象间的动态关系。
C++设计模式
工厂模式
工厂模式:主要是封装了对象的创建。
简单工厂(Simple Factory):
优点:
- 把对象的创建封装在一个接口函数里面,通过传入不同的标识,返回创建的对象。
- 使用者不需要自己负责new对象,不用了解对象创建的详细过程。
缺点:
- 提供创建对象实例的接口函数不闭合,不能对修改关闭。
工厂方法(Factory Method):
优点:
- 使用Factory基类,提供一个纯虚函数(创建产品),定义派生类(具体产品的工厂)负责创建对应的产品,可以做到不同的产品在不同的工厂进行创建。能对现有工厂以及产品的修改关闭
缺点:
- 忽略了产品之间的关联关系,属于一个产品簇的不应该放到不同的工厂里面去创建。不符合产品对象创建逻辑;
- 工厂类太多,难以维护。
抽象工厂(Abstact Factory)
优点:
- 把现有关联关系、属于同一个产品簇的所有产品创建的接口函数放在一个抽象工厂里面,派生类(具体产品的工厂)应该负责创建该产品簇里面的所有产品。
这里使用了一个汽车生产的工厂示例,列举了简单工厂和工厂方法,并使用智能指针进行对象空间优化回收。
简单工厂和工厂方法
#include <iostream>
#include <string>
#include<memory>using namespace std;class Car
{
public:Car(string name):_name(name){}virtual void show() = 0; //定义纯虚函数,子类必须实现protected:string _name;private:
};
class BMW:public Car
{
public:// 使用Car(name)类似于_name(name),还是用了Car的_name,// 子类继承父类的构造函数可以参考 https://blog.csdn.net/aquapisces/article/details/104371658BMW(string name) : Car(name){};void show(){cout << "获取了一辆宝马汽车" << _name << endl;}
protected :
private:
};
class Audi : public Car
{
public:// 使用Car(name)类似于_name(name),还是用了Car的_name,// 子类继承父类的构造函数可以参考 https://blog.csdn.net/aquapisces/article/details/104371658Audi(string name) : Car(name){};void show(){cout << "获取了一辆奥迪汽车" << _name << endl;}protected:
private:
};// ------------------------------------------------------------------------------------------
/*
简单工厂存在以下问题:开闭原则,新增一个汽车则需要修改很多代码;BMW类和Audi类都在一个工厂里面生产
*/
enum CarType
{bmw,audi
};
class SimpleFactory
{
public:Car* createCar(CarType ct){switch (ct){case bmw:return new BMW("X1");case audi:return new Audi("A6");default:cout << "传入工厂的参数不正确:" << ct << endl;break;}return nullptr;}
};
// ------------------------------------------------------------------------------------------
/*
工厂方法
*/
class Factory
{
public:virtual Car* createCar(string name) = 0;
};
class BMWFactory:public Factory
{
public:Car* createCar(string name){return new BMW(name);}
};
class AudiFactory : public Factory
{
public:Car *createCar(string name){return new Audi(name);}
};
// ------------------------------------------------------------------------------------------int main()
{// unique_ptr无法进行普通拷贝构造和赋值unique_ptr<Car> p1=new BMW("X1");是错误的// 最原始的对象产生unique_ptr<Car> p1(new BMW("X1"));unique_ptr<Car> p2(new Audi("A6"));// 简单工厂// unique_ptr<SimpleFactory> factory(new SimpleFactory());// unique_ptr<Car> p1(factory->createCar(bmw));// unique_ptr<Car> p2(factory->createCar(audi));// 工厂方法// unique_ptr<Factory> bmwFactory(new BMWFactory);// unique_ptr<Factory> audiFactory(new AudiFactory);// unique_ptr<Car> p1(bmwFactory->createCar("X6"));// unique_ptr<Car> p2(audiFactory->createCar("A8"));p1->show();p2->show();return 0;
}
抽象工厂方法
上一节中的工厂方法会存在一个问题,在定义了一个Factory
抽象类后,每一个类将对应一个类的工厂,如BWM->BMWFactory
,Audi->AudiFactory
,这样会导致一个问题,在生产一类产品时,如手机充电器和充电线,那么就又需要两个工厂来实现,所以这样就会导致工厂冗余。所以,提出了抽象工厂来解决这个问题,这里以汽车的生产部件为例进行说明:
#include <iostream>
#include <string>
#include<memory>using namespace std;class Car
{
public:Car(string name):_name(name){}virtual void show() = 0; //定义纯虚函数,子类必须实现protected:string _name;private:
};
class BMW:public Car
{
public:// 使用Car(name)类似于_name(name),还是用了Car的_name,// 子类继承父类的构造函数可以参考 https://blog.csdn.net/aquapisces/article/details/104371658BMW(string name) : Car(name){};void show(){cout << "获取了一辆宝马汽车" << _name << endl;}
protected :
private:
};
class Audi : public Car
{
public:// 使用Car(name)类似于_name(name),还是用了Car的_name,// 子类继承父类的构造函数可以参考 https://blog.csdn.net/aquapisces/article/details/104371658Audi(string name) : Car(name){};void show(){cout << "获取了一辆奥迪汽车" << _name << endl;}protected:
private:
};class Light
{
public:virtual void show() = 0;
};class BMWLight:public Light
{
public:void show(){cout << "BMW light!" << endl;}
};class AudiLight : public Light
{
public:void show(){cout << "Audi light!" << endl;}
};
/*
抽象工厂,对一组关联关系的产品簇提供产品对象的统一创建。
有点类似于工厂方法
*/
class AbstractFactory
{
public:virtual Car *createCar(string name) = 0;virtual Light *createCarLight() = 0;
};
class BMWFactory : public AbstractFactory
{
public:Car *createCar(string name){return new BMW(name);}Light *createCarLight(){return new BMWLight();}
};
class AudiFactory : public AbstractFactory
{
public:Car *createCar(string name){return new Audi(name);}Light *createCarLight(){return new AudiLight();}
};int main()
{// 抽象工厂方法unique_ptr<AbstractFactory> bmwFactory(new BMWFactory);unique_ptr<AbstractFactory> audiFactory(new AudiFactory);unique_ptr<Car> p1(bmwFactory->createCar("X6"));unique_ptr<Car> p2(audiFactory->createCar("A8"));unique_ptr<Light> l1(bmwFactory->createCarLight());unique_ptr<Light> l2(audiFactory->createCarLight());p1->show();p2->show();l1->show();l2->show();return 0;
}
代理模式
代理(proxy)模式:通过代理类,来控制实际对象的访问权限。其实也就是定义一个虚基类,子类继承虚基类实现不同级别对象的实现,可以看以下类似代码:
#include <iostream>
#include <string>
#include<memory>using namespace std;class VideoSite
{
public:virtual void freeMovie() = 0;virtual void vipMovie() = 0;virtual void ticketMovie() = 0;
};
class FixBugVideoSite:public VideoSite
{// 不同的用户的访问权限可能不够,所以下面三个函数有些对象不能调用void freeMovie(){cout << "观看免费电影" << endl;}void vipMovie(){cout << "观看vip电影" << endl;}void ticketMovie(){cout << "观看电影券电影" << endl;}
};// 代理类,用于代理FixBugVideoSite
class FreeVideoSiteProxy:public VideoSite
{
public:FreeVideoSiteProxy(){pVideo = new FixBugVideoSite();}~FreeVideoSiteProxy(){if(pVideo!=nullptr){delete pVideo;}pVideo = nullptr;}void freeMovie(){pVideo->freeMovie();}void vipMovie(){cout << "您目前只是普通用户,需要升级成vip才能观看vip电影" << endl;}void ticketMovie(){cout << "您目前只是普通用户,需要购买电影券才能观看电影" << endl;}private:VideoSite *pVideo;
};
class VipVideoSiteProxy : public VideoSite
{
public:VipVideoSiteProxy(){pVideo = new FixBugVideoSite();}~VipVideoSiteProxy(){if (pVideo != nullptr){delete pVideo;}pVideo = nullptr;}void freeMovie(){pVideo->freeMovie();}void vipMovie(){pVideo->vipMovie();}void ticketMovie(){cout << "您目前只是普通用户,需要购买电影券才能观看电影" << endl;}private:VideoSite *pVideo;
};
int main()
{// unique_ptr<VideoSite> p1(new FreeVideoSiteProxy());unique_ptr<VideoSite> p1(new VipVideoSiteProxy());p1->freeMovie();p1->vipMovie();p1->ticketMovie();return 0;
}
观察者模式
行为型模式:主要关注的是对象之间的通信。
以观察者-监听者模式(发布-订阅模式)设计模式:主要关注的是对象的一对多的关系,也就是多个对象都依赖一个对象,当该对象的状态发生改变时,其他对象都能够结束到相应的通知。
ps:一组数据改变(数据对象)->通过这一组数据->曲线图(对象1)/柱状图(对象2)/圆饼图(对象3)。当数据对象改变时,对象1、对象2、对象3应该及时的收到相应的通知。
#include <iostream>
#include <string>
#include<list>
#include<unordered_map>using namespace std;
/**
观察者模式/订阅模式:当一个对象发生改变时,会通知其他对象去处理对象的事件。
*/
class Observer
{
public:virtual void handle(int msgid) = 0;
};
class Observer1:public Observer
{void handle(int msgid){switch (msgid){case 1:cout << "observer1 recv 1 msg." << endl;break;case 2:cout << "observer1 recv 2 msg." << endl;break;default:cout << "observer1 recv unknow msg." << endl;break;}}
};
class Observer2 : public Observer
{void handle(int msgid){switch (msgid){case 3:cout << "observer2 recv 3 msg." << endl;break;case 2:cout << "observer2 recv 2 msg." << endl;break;default:cout << "observer2 recv unknow msg." << endl;break;}}
};
class Observer3 : public Observer
{void handle(int msgid){switch (msgid){case 1:cout << "observer3 recv 1 msg." << endl;break;case 3:cout << "observer3 recv 3 msg." << endl;break;default:cout << "observer3 recv unknow msg." << endl;break;}}
};
class Subjects
{
public:// 给主题添加观察者对象void addObserver(Observer* obser,int msgid){// 和下面的操作一致,如果存在msgid为key的情况就直接插入,没有就创建一个并插入_submap[msgid].push_back(obser);/**// 查找map中是否存在有key为msgid的值auto it = _submap.find(msgid);if(it != _submap.end()){it->second.push_back(obser);}else{list<Observer *> olist;olist.push_back(obser);_submap.insert(make_pair(msgid, olist));}*/}// 主题检测发生改变,通知相应的观察者对象处理事件void dispatch(int msg){auto it = _submap.find(msg);if (it != _submap.end()){for(Observer* pObser:it->second){pObser->handle(msg);}}}
private:unordered_map<int, list<Observer *>> _submap;
};
int main()
{Subjects sub;Observer *p1 = new Observer1();Observer *p2 = new Observer2();Observer *p3 = new Observer3();sub.addObserver(p1, 1);sub.addObserver(p2, 3);sub.addObserver(p3, 1);sub.addObserver(p3, 2);sub.addObserver(p1, 3);sub.dispatch(2);return 0;
}
适配器模式
适配器模式:让不兼容的接口可以在一起工作。
下方使用C++实现了一个电脑播放投影视频的例子,电脑仅仅支持VGA接口,如何实现HDMI接口转化成VGA来适配电脑使用。也就是如何实现一个VGA和HEMI类的转化接口。
#include <iostream>
#include <string>using namespace std;class VGA
{
public:virtual void play() = 0;
};
class TV01:public VGA
{
public:void play() { cout << "通过VGA接口连接投影仪,进行视频播放!" << endl; }
};class HDMI
{
public:virtual void play() = 0;
};
class TV02 : public HDMI
{
public:void play() { cout << "通过HDMI接口连接投影仪,进行视频播放!" << endl; }
};// 一定要继承原来的类
class VGA2HDMIAdapter:public VGA
{
public:VGA2HDMIAdapter(HDMI* p):phdmi(p){}void play() { phdmi->play(); }private:HDMI *phdmi;
};
class Computer
{
public:// 由于电脑只支持VGA接口,所以该方法的参数也只支持VGA接口的指针/引用void playVideo(VGA *pVGA) { pVGA->play(); }
};int main()
{// HDMI和VGA无法进行互相转化,电脑如何使用HDMI的play方法?/*1、换一个支持HDMI的电脑,也就是对Computer类进行重构,叫做代码重构。2、使用一个适配器(转化头),把VGA类转化为HDMI类,叫做添加适配器类。*/Computer computer;computer.playVideo(new TV01());computer.playVideo(new VGA2HDMIAdapter(new TV02()));return 0;
}
装饰器模式
装饰器(decorate)模式和代理模式类似。代理模式也就是定义委托类和代理类继承抽象类,并重写函数方法,通过在代理类中使用委托类的对象调用不同级别代理的方法访问。
装饰器主要是增加现有类的功能,但是添加现有类的一个方法还有一个方法,就是新建一个子类。如果每次新建一个功能都需要新建一个子类的话,那么代码中就会有很多的子类被添加进来。
以下实现了一个汽车装饰类的代码实现:
#include <iostream>
#include <string>using namespace std;class Car
{
public:virtual void show() = 0;
};
class BMW : public Car
{
public:void show() { cout << "这是一辆宝马汽车!有基本配置"; }
};
class Audi : public Car
{
public:void show() { cout << "这是一辆奥迪汽车!有基本配置"; }
};
class Benc : public Car
{
public:void show() { cout << "这是一辆奔驰汽车!有基本配置"; }
};
// 装饰器
class CarDecorator01 : public Car
{
public:CarDecorator01(Car *p) : pCar(p){};void show(){pCar->show();cout << ",辅助驾驶";}
private: Car *pCar;
};
class CarDecorator02 : public Car
{
public:CarDecorator02(Car *p) : pCar(p){};void show(){pCar->show();cout << ",自动校正";}private:Car *pCar;
};
class CarDecorator03 : public Car
{
public:CarDecorator03(Car *p) : pCar(p){};void show(){pCar->show();cout << ",车道偏离";}private:Car *pCar;
};
int main()
{Car *p1 = new CarDecorator01(new BMW());p1 = new CarDecorator02(p1);p1->show();cout << endl;Car *p2 = new CarDecorator02(new Audi());p2->show();cout << endl;Car *p3 = new CarDecorator03(new Benc());p3->show();cout << endl;return 0;
}
单例模式
常见的类创建一个对象,便会得到一个新的对象。而单例模式则有些不同。
单例模式:一个类不管创建多少次对象,永远只能得到该类型一个对象的实例。可以查看C++实现MySQL数据库连接池中的线程池获取代码,将线程池定义为静态成员方法和静态成员变量,导致其处于静态变量区,只需要初始化一次。类似的日志模块应该也可以使用单例模式。
饿汉式单例模式:还没有获取实例对象,实例对象就已经产生了。
懒汉式单例模式:唯一的实例对象,直到第一次获取它的时候才产生。
下面介绍了两种单例模式的代码设计,其中提供了两种懒汉式单例模式的示例:
#include <iostream>
#include <string>
#include<mutex>
using namespace std;// 饿汉式单例模式,线程安全的
class HungrySingleton
{
public:// 因为其不能依赖对象,所以要定义成静态成员方法,获取类的唯一实例对象的方法static HungrySingleton* getSingleton(){return &instance;}
private:// 单例模式,不允许用户new对象,所以需要使用构造函数私有化HungrySingleton(){}static HungrySingleton instance;// 将拷贝构造函数和赋值操作符重载进行删除,使其不能完成对象创建,只能依赖getSingleton过去唯一的实例化对象HungrySingleton& operator=(const HungrySingleton &) = delete;HungrySingleton(const HungrySingleton &) = delete;
};
// 类内定义,类外初始化,更多static初始化查看 https://blog.csdn.net/sevenjoin/article/details/81772792
// 静态成员在数据段,在main函数之前就创建了,如果不使用的话,这个资源就浪费了
HungrySingleton HungrySingleton::instance;mutex lazySingletonMtx;// 懒汉式单例模式,线程安全的
class LazySingleton
{
public:// 因为其不能依赖对象,所以要定义成静态成员方法,获取类的唯一实例对象的方法// 可重入函数的概念?一个线程还没执行完,该函数不能被另一个线程执行,也就是线程互斥static LazySingleton *getSingleton(){ if(instance==nullptr){lock_guard<mutex> lck(lazySingletonMtx); // 所以多线程环境下需要加锁和双重判断/*不是线程安全,下面这个instance = new LazySingleton()需要执行-:开辟内存、构造对象、instance赋值*/if(instance==nullptr){ // 双重判断,防止两个线程同时进入上层的if判断中instance = new LazySingleton();}}return instance;}private:// 单例模式,不允许用户new对象,所以需要使用构造函数私有化LazySingleton(){}static LazySingleton*volatile instance;// 将拷贝构造函数和赋值操作符重载进行删除,使其不能完成对象创建,只能依赖getSingleton过去唯一的实例化对象LazySingleton &operator=(const LazySingleton &) = delete;LazySingleton(const LazySingleton &) = delete;
};
// 类内定义,类外初始化,更多static初始化查看 https://blog.csdn.net/sevenjoin/article/details/81772792
// 静态成员在数据段,在main函数之前就创建了,如果不使用的话,这个资源就浪费了
LazySingleton*volatile LazySingleton::instance=nullptr;// 懒汉式单例模式,线程安全的
class LazySingleton2
{
public:// 因为其不能依赖对象,所以要定义成静态成员方法,获取类的唯一实例对象的方法// 可重入函数的概念?一个线程还没执行完,该函数不能被另一个线程执行,也就是线程互斥static LazySingleton2 *getSingleton(){// 静态对象,运行到这个函数才开始初始化// 函数静态局部变量的初始化,在汇编指令上已经自动添加线程互斥指令static LazySingleton2 instance;return &instance;}private:// 单例模式,不允许用户new对象,所以需要使用构造函数私有化LazySingleton2(){}// 将拷贝构造函数和赋值操作符重载进行删除,使其不能完成对象创建,只能依赖getSingleton过去唯一的实例化对象LazySingleton2 &operator=(const LazySingleton2 &) = delete;LazySingleton2(const LazySingleton2 &) = delete;
};int main()
{HungrySingleton *p1 = HungrySingleton::getSingleton();HungrySingleton *p2 = HungrySingleton::getSingleton();HungrySingleton *p3 = HungrySingleton::getSingleton();cout << p1 << " " << p2 << " " << p3 << endl; // 0x407030 0x407030 0x407030LazySingleton *p4 = LazySingleton::getSingleton();LazySingleton *p5 = LazySingleton::getSingleton();LazySingleton *p6 = LazySingleton::getSingleton();cout << p4 << " " << p5 << " " << p6 << endl; // 0x25d2430 0x25d2430 0x25d2430// HungrySingleton t = *p1; // 拷贝构造函数私有化之后就不能完成拷贝构造了return 0;
}
一般情况下第二种懒汉式单例模式用的比较多,也更简单,在静态成员方法中定义静态成员对象。
相关文章:

C++设计模式笔记
设计模式 如何解决复杂性? 分解 核心思想:分而治之,将大问题分解为多个小问题,将复杂问题分解为多个简单的问题。 抽象 核心思想:从高层次角度讲,人们处理复杂性有一个通用的技术,及抽象。…...

简单聊聊创新与创造力
文章目录 前言一、大脑运行的两种方式1、聚焦模式2、发散模式3、影响想法的因素a、背景知识b、兴趣c、天赋 4、思维固化 二、想法的不可靠1、对想法进行验证2、颠覆性创新,挤牙膏式创新3、为什么模仿这么多 三、更多更多的idea1、个人的方面a、积累不同的背景知识b、…...

使用TensorFlow训练深度学习模型实战(上)
大家好,尽管大多数关于神经网络的文章都强调数学,而TensorFlow文档则强调使用现成数据集进行快速实现,但将这些资源应用于真实世界数据集是很有挑战性的,很难将数学概念和现成数据集与我的具体用例联系起来。本文旨在提供一个实用…...

【Spring】什么是Bean的生命周期及作用域,什么是Spring的执行流程?
博主简介:想进大厂的打工人博主主页:xyk:所属专栏: JavaEE进阶 在前面的播客中讲解了如何从Spring中存取Bean对象,那么本篇我们来讲解Bean对象的生命周期是什么,Bean对象的6种作用域分别是什么,都有哪些区别ÿ…...

立创EDA学习
学习树莓派3B的板子发现有个扩展板比较好,自己最好画一个,反正免费。 学习视频:立创EDA(专业版)电路设计与制作快速入门。 下载专业版,并激活。【分专业版和标准版,专业版也是免费的】 手机…...
清风学习笔记—层次分析法—matlab对判断矩阵的一致性检验
在判断矩阵是否为正互反矩阵这块,我写了两种代码,改进前很麻烦且有错误,改进后简洁多了,改进前的代码还有错误,忽略了对角线的值必须都是1,只考虑了除开对角线的元素相乘为1。 %% 改进前代码 A[3 2 4;1/2 …...
大众安徽内推
大众汽车(安徽)有限公司是大众汽车集团在中国第一家专注于新能源汽车的合资企业,是集团在中国首家拥有全面运营管理权的合资企业,担负着产品研发及数字化研发的重任,将成为集团全球电动出行中心之一。 VW Anhui Offic…...

Meta “地平线世界”移动端应用即将上线,手机快乐元宇宙?
根据海外记者 Janko Roettgers 的报道,Meta 预计很快推出移动版的 VR 元宇宙服务 "地平线世界",这是Meta 长期开发的产品。 根据最新报道,Meta宣布正在研发“地平线世界”的移动版,并表示这一服务已经可以在Quest VR设…...

更省更快更安全的云服务器,一站式集中管理,随时随地远程——站斧云桌面
随着全球化和数字化经济的发展,越来越多的企业开始海外扩张和拓展国际市场。而云服务器作为一种高效、灵活且可靠的IT基础设施方案,已成为出海企业不可或缺的重要工具。这里就为大家介绍云服务器在出海企业中的几个使用场景。 1.全球范围内协同办公 对…...
出现 Try run Maven import with -U flag (force update snapshots) 的解决方法
目录 1. 问题所示2. 原理分析3. 解决方法1. 问题所示 在配置Maven依赖信息的时候,出现如下问题: com.alibaba.nacos:nacos‐client:pom:1.1.3 failed to transfer from http://nexus.hepengju.cn:8081/nexus/content/groups/public/ during a previous attempt. This failu…...

python多线程
目录 一.多线程的定义 A.什么是多线程? B.多线程如今遇到的挑战 C.总结 二.python中的多线程 A.python中的多线程底层原理: B.全局解释器锁导致python多线程不能实现真正的并行执行! C.总结应用场景 三.java多线程,以及…...
Spring Framework 提供缓存管理器Caffeine
说明 Spring Framework 提供了一个名为 Caffeine 的缓存管理器。Caffeine 是一个基于 Java 的高性能缓存库,被广泛用于处理大规模缓存数据。 使用 Caffeine 缓存管理器,可以轻松地在 Spring 应用程序中添加缓存功能。它提供了以下主要特性:…...
ZQC的游戏 题解
前言 这题题意描述不是很清楚啊,所以我找了个有权限的人把题面改了改,应该还是比较清楚了。 感觉这道题挺妙的,就来写一篇题解。 思路 首先,根据贪心思想,我们会将 1 1 1 号点半径以内能吃的都吃了,假…...

24考研数据结构-第一章 绪论
数据结构 引用文章第一章:绪论1.0 数据结构在学什么1.1 数据结构的基本概念1.2 数据结构的三要素1.3 算法的基本概念1.4 算法的时间复杂度1.4.1 渐近时间复杂度1.4.2 常对幂指阶1.4.3 时间复杂度的计算1.4.4 最好与最坏时间复杂度 1.5 算法的空间复杂度1.5.1 空间复…...

Gitlab 备份与恢复
备份 1、备份数据(手动备份) gitlab-rake gitlab:backup:create2、备份数据(定时任务备份) [rootlocalhost ]# crontab -l 00 1 * * * /opt/gitlab/bin/gitlab-rake gitlab:backup:create 说明:每天凌晨1点备份数据…...

数据库—用户权限管理(三十三)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、概述 二、用户权限类型 三、用户赋权 四、权限删除 五、用户删除 前言 数据库用户权限管理是指对数据库用户的权限进行控制和管理,确保用户只能执…...
C语言【怎么定义变量?】
变量定义的目的是向编译器说明在哪里创建变量的存储,并指明如何创建变量的存储方式。变量定义会明确指定一个数据类型,并包含一个或多个变量的列表。例如: type variable_list; 在这里,"type"必须是一个合法的C数据类…...

vue中使用vab-magnifier实现放大镜效果
效果图如下: 1. 首先,使用npm或yarn安装vab-magnifier插件: npm install vab-magnifier或 yarn add vab-magnifier2. 在Vue组件中引入vab-magnifier插件: import VabMagnifier from vab-magnifier; import vab-magnifier/lib…...

无涯教程-jQuery - Highlight方法函数
Highlight 效果可以与effect()方法一起使用。这将以特定的颜色突出显示元素的背景,默认为黄色(yellow)。 Highlight - 语法 selector.effect( "highlight", {arguments}, speed ); 这是所有参数的描述- color - 高亮显示颜色。默认值为"#fff…...

【bar堆叠图形绘制】
绘制条形图示例 在数据可视化中,条形图是一种常用的图表类型,用于比较不同类别的数据值。Python的matplotlib库为我们提供了方便易用的功能来绘制条形图。 1. 基本条形图 首先,我们展示如何绘制基本的条形图。假设我们有一个包含十个类别的…...

Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现指南针功能
指南针功能是许多位置服务应用的基础功能之一。下面我将详细介绍如何在HarmonyOS 5中使用DevEco Studio实现指南针功能。 1. 开发环境准备 确保已安装DevEco Studio 3.1或更高版本确保项目使用的是HarmonyOS 5.0 SDK在项目的module.json5中配置必要的权限 2. 权限配置 在mo…...

Matlab实现任意伪彩色图像可视化显示
Matlab实现任意伪彩色图像可视化显示 1、灰度原始图像2、RGB彩色原始图像 在科研研究中,如何展示好看的实验结果图像非常重要!!! 1、灰度原始图像 灰度图像每个像素点只有一个数值,代表该点的亮度(或…...

边缘计算网关提升水产养殖尾水处理的远程运维效率
一、项目背景 随着水产养殖行业的快速发展,养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下,而且难以实现精准监控和管理。为了提升尾水处理的效果和效率,同时降低人力成本,某大型水产养殖企业决定…...