C++常见设计模式

news2024/11/19 9:32:55

设计模式

设计模式的六大原则:https://zhuanlan.zhihu.com/p/110130347

适配器模式

假设Client想要一个正方形(client Interface),但是提供的服务(service)是个圆形,那么我就把这个圆通过适配器(adapter)装到正方形里,adapter继承了正方形的接口,你以为你用的是个正方形,实际上里面是个圆。
优点:
单一职责原则:可以将接口或数据转换代码从程序主要业务逻辑中分离。
开闭原则: 只要客户端代码通过客户端接口与适配器进行交互,你就能在不修改现有客户端代码的情况下在程序中添加新类型的适配器。
缺点:
代码整体复杂度增加

#include<iostream>
using namespace std;

//Target:客户端需要的目标接口,适配器你往哪转
class JsonInfo
{
public:
        virtual ~JsonInfo() {}
        //这个就是读取的json信息,我们要实现的其实就是xml转为json
        virtual string resquest() const 
        {
                return "Some Json msg.......";
        }
};

//Adaptee: 需要转换的目标,客户端不兼容的接口,需要转换为Target
class XmlInfo
{
public:
        string specialResquest() const
        {
                return "Some Xml msg.......";
        }
};

//Adapter: 适配器,把Adaptee包装起来,让他看上去像是Target
//我们是要转为json,所以需要继承,这样才可以看上去像json
class XmlJsonAdapter :public JsonInfo
{
        
public:
        XmlJsonAdapter(XmlInfo* adptee) :m_adptee(adptee) {}

        virtual string resquest() const override
        {
                string string = m_adptee->specialResquest();
                return "Json->XmlJsonAdapter->XmlInfo";
        }
private:
        //通过对象的方式把XmlInfo内容给包住
        XmlInfo* m_adptee;
};

//表示长图的client
void clientCode(const JsonInfo* info)
{
        cout << "股票分析软件Json: " << info->resquest()<< endl;
        cout << "-----------------------" << endl;
}


int main()
{
        JsonInfo jsonInfo;
        clientCode(&jsonInfo);
        XmlInfo xmlInfo;
        XmlJsonAdapter jsonAdapter(&xmlInfo);
        clientCode(&jsonAdapter);
        return 0;
}

经典的“方钉圆孔问题”
在这里插入图片描述

/*
有一个圆孔,可以把圆钉放进去,但现在只能提供方钉,所以需要一个适配器,把方钉裹成圆钉,就可以被适配器调用了。
获得裹后圆钉的半径,方钉的宽度除2再乘根号2

圆孔就相当于client,圆钉表示客户端可以处理的类型,方钉相当于服务器提供的类型
*/
#include<iostream>
using namespace std;

//定义圆钉
class RoundPeg
{
public:
        RoundPeg(){}
        virtual ~RoundPeg() {}
        RoundPeg(const double& r) :m_radius(r) {};
        virtual int getRadius() const
        {
                return this->m_radius;
        }
private:
        int m_radius;
};

//定义方钉
class SqurePeg
{
public:
        virtual ~SqurePeg() {};
        SqurePeg(const int& wid) :m_wid(wid) {};
        int getWidth()
        {
                return m_wid;
        }
private:
        int m_wid;
};

//定义圆孔
class RoundHole
{
public:
        RoundHole(const int& r) :radius(r) {}
        int getRadius()
        {
                return this->radius;
        }
        bool fits(RoundPeg* roundPeg)
        {
                if (radius < roundPeg->getRadius())
                        return false;
                else
                        return true;
        }
private:
        int radius;
};


//定义适配器,继承自圆钉
class Adapter : public RoundPeg
{
public:
        Adapter(SqurePeg* adptee) :m_adptee(adptee) {}
        int getRadius() const override
        {
                int r = m_adptee->getWidth() * sqrt(2) / 2;
                return r;
        }

private:
        SqurePeg* m_adptee;
};


int main()
{
        //定义圆孔
        RoundHole hole =  RoundHole(5);
        //定义圆钉
        RoundPeg r_peg1 = RoundPeg(3);
        RoundPeg r_peg2 = RoundPeg(10);
        //定义方钉
        SqurePeg s_peg1 = SqurePeg(2);
        SqurePeg s_peg2 = SqurePeg(10);

        bool res = hole.fits(&r_peg1);

        if (res) cout << "r_peg1 畅通无阻" << endl;
        else cout << "r_peg1 堵死" << endl;

        res = hole.fits(&r_peg2);
        if (res) cout << "r_peg2 畅通无阻" << endl;
        else cout << "r_peg2 堵死" << endl;

        Adapter adapter(&s_peg1);
        res = hole.fits(&adapter);
        if (res) cout << "s_peg1 畅通无阻" << endl;
        else cout << "s_peg1 堵死" << endl;

        Adapter adapter2(&s_peg2);
        res = hole.fits(&adapter2);
        if (res) cout << "s_peg2 畅通无阻" << endl;
        else cout << "s_peg2 堵死" << endl;

        return 0;
}

单例模式

单例模式:一个类不管创建多少次对象,永远只能得到该类型的一个实例。像日志模块,数据库模块就会用到。
个人理解,单例本质上就是全局变量,只不过是又包装了一层。

饿汉式单例模式:

饿汉式单例,即使没调用对象,static Singleton instance;也会实例化,因为存在数据段,会在main执行前执行初始化。
一定是线程安全的,线程函数启动前实例就会初始化好。
缺点:对象的实例化会调用构造函数,但是这个构造函数在实际应用时,会构造很多东西,比如加载配置文件什么的,要是不使用这些东西,构造的不就浪费了,白费时间

 #include<iostream>
 using namespace std;
 
 class Singleton
 {
 public:
     //3 获取类的唯一实例对象的接口方法
     static Singleton* getInstance()
     {
         return &instance;
     }
 
 private:
     //2 定义一个唯一类的实例对象
     static Singleton instance;
 
     //1 构造函数私有化,并禁止拷贝构造和赋值构造
     Singleton()
     {
 
     }
     Singleton(const Singleton&) = delete;
     Singleton& operator=(const Singleton&) = delete;
 };
 
 Singleton Singleton::instance;
 
 
 int main()
 {
     Singleton* p1 = Singleton::getInstance();
     Singleton* p2 = Singleton::getInstance();
     return 0;
 }

懒汉式单例实现模式:
把对象的实例化延迟到第一次获取该实例对象的时候
线程安全的单例模式-使用互斥锁加双重判断

#include<iostream>
 #include<mutex>
 
 using namespace std;
 
 mutex mtx;
 
 class Singleton
 {
 public:
     //3 获取类的唯一实例对象的接口方法
     //锁加双重判断
     static Singleton* getInstance()
     {
         //lock_guard<mutex> guard(mtx); //锁的粒度太大了,单线程完全不用这样
         if (instance == nullptr)
         {
             lock_guard<mutex> guard(mtx);
             /*
             开辟内存
             构造对象
             给instance赋值
             */
             if (instance == nullptr)
             {
                 instance = new Singleton();
             }
         }//出括号释放锁
         return instance;
     }
 
 private:
     //2 定义一个唯一类的实例对象 存放在数据段
     static Singleton volatile instance;  //加上volatile后,当一个线程对instance改变,其他线程立马就能看到改变了,看的都是内存里的值
 
     //1 构造函数私有化,并禁止拷贝构造和赋值构造
     Singleton()
     {
 
     }
     Singleton(const Singleton&) = delete;
     Singleton& operator=(const Singleton&) = delete;
 };
 
 Singleton* volatile Singleton::instance=nullptr;
 
 
 int main()
 {
     Singleton* p1 = Singleton::getInstance();
     Singleton* p2 = Singleton::getInstance();
     return 0;
 }

上面的代码可以关注下 volatile 的用法。

观察者模式

主要关注的是对象之间的一对多通信,也就是多个对象都依赖一个对象,当该对象状态发生改变的时候,其他对象都能够接收到相应的通知。

#include<iostream>
#include<unordered_map>
#include<list>
using namespace std;

class Observer
{
public:
        //处理消息的接口
        virtual void handle(int msgid) = 0;
};

//观察者1
class Observer1 :public Observer
{
public:
        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 unknown msg!" << endl;
                        break;
                }
        }
};

//观察者2
class Observer2 :public Observer
{
public:
        void handle(int msgid)
        {
                switch (msgid)
                {
                case 2:
                        cout << "Observer2 recv 2 msg!" << endl;
                        break;
                default:
                        cout << "Observer2 recv unknown msg!" << endl;
                        break;
                }
        }
};

//观察者3
class Observer3 :public Observer
{
public:
        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 unknown msg!" << endl;
                        break;
                }
        }
};

class Subject
{
public:
        void addObserver(Observer* obs, int msgid)
        {
                //使用unordered_map,重载的[]运算符,如果找到了就直接插入,找不到会重新创建
                subMap[msgid].push_back(obs);
        }

        //主题检测发生变化,通知相应的观察者对象处理事件
        void dispatch(int msgid)
        {
                auto it = subMap.find(msgid);
                if (it != subMap.end())
                {
                        for (auto pObs : it->second)
                        {
                                pObs->handle(msgid);
                        }
                }
        }
private:
        //使用一个map存储哪个观察者对哪个消息感兴趣
        unordered_map<int, list<Observer*>> subMap;
};


int main()
{
        Subject subject;
        Observer* p1 = new Observer1();
        Observer* p2 = new Observer2();
        Observer* p3 = new Observer3();

        subject.addObserver(p1, 1);
        subject.addObserver(p1, 2);
        subject.addObserver(p2, 2);
        subject.addObserver(p3, 1);
        subject.addObserver(p3, 3);

        int msgid = 0;
        for (;;)
        {
                cout << "输入消息ID:";
                cin >> msgid;
                if (msgid == -1)
                        break;
                subject.dispatch(msgid);
        }

        return 0;
}

代理模式

这里主要说的是保护代理,即给不同的用户提供不同的对象访问权限。
通过代理类,来控制实际对象的访问权限。
下面的代码,主要是实现了用户观看普通电影,VIP电影,用券影的相关权限。

#include<iostream>
using namespace std;

//抽象类
class VideoSite
{
public:
        virtual void freeVideo() = 0;
        virtual void vipVideo() = 0;
        virtual void ticketVideo() = 0;
};

//委托类
class FixBugVideoSite :public VideoSite
{
        virtual void freeVideo()
        {
                cout << "观看免费电影" << endl;
        }
        virtual void vipVideo()
        {
                cout << "观看免费电影" << endl;
        }
        virtual void ticketVideo()
        {
                cout << "观看免费电影" << endl;
        }
};

//代理类 代理委托类
class FreeVideoSite :public VideoSite
{
public:
        FreeVideoSite() { pVideo = new FixBugVideoSite(); }
        ~FreeVideoSite() { delete pVideo; }
        //必须全部重写这些方法,要是不重写,代理类本身也成抽象类了
        void freeVideo()
        {
                pVideo->freeVideo();
        }
        void vipVideo()
        {
                cout << "您是普通用户,请升级VIP后观看" << endl;
        }
        void ticketVideo()
        {
                cout << "您未购买券,请购买后观看" << endl;
        }
private:
        VideoSite* pVideo;
};

class VipVideoSite :public VideoSite
{
public:
        VipVideoSite() { pVideo = new FixBugVideoSite(); }
        ~VipVideoSite() { delete pVideo; }
        //必须全部重写这些方法,要是不重写,代理类本身也成抽象类了
        void freeVideo()
        {
                cout << "观看普通电影" << endl;
        }
        void vipVideo()
        {
                pVideo->vipVideo();
        }
        void ticketVideo()
        {
                cout << "您未购买券,请购买后观看" << endl;
        }
private:
        VideoSite* pVideo;
};

class ticketVideoSite :public VideoSite
{
public:
        ticketVideoSite() { pVideo = new FixBugVideoSite(); }
        ~ticketVideoSite() { delete pVideo; }
        //必须全部重写这些方法,要是不重写,代理类本身也成抽象类了
        void freeVideo()
        {
                cout << "观看普通电影" << endl;
        }
        void vipVideo()
        {
                cout << "观看VIP电影" << endl;
        }
        void ticketVideo()
        {
                pVideo->ticketVideo();
        }
private:
        VideoSite* pVideo;
};

void showMovie(VideoSite* ptr)
{
        ptr->freeVideo();
        ptr->vipVideo();
        ptr->ticketVideo();
}

int main()
{
        VideoSite* p1 = new FreeVideoSite();
        VideoSite* p2 = new ticketVideoSite();
        showMovie(p1);
        showMovie(p2);
        delete p1;
        delete p2;
        return 0;
}

简单工厂模式

在创建的类比较多的时候可以使用工厂模式,主要是封装了对象的创建。
把这些对象都封装到一个工厂类里面,不需要知道这个对象是怎么创建的,就比如士兵上战场,只需要给他一把枪就可以了,不需要让他再new一个枪出来。
不符合开闭原则

#include<iostream>
#include<memory>
using namespace std;

//工厂模式主要是封装了对象的创建
/*
简单工厂模式
不符合开放封闭原则
如果要多加几个工厂,就得修改switch
*/
class Car
{
public:
        Car(string name) :m_name(name) {};
        virtual void show() = 0;
protected:
        string m_name;
};

class Bmw : public Car
{
public:
        Bmw(string name) :Car(name) {}
        void show()
        {
                cout << "购买了一辆宝马:" << m_name << endl;
        }
};

class Audi : public Car
{
public:
        Audi(string name) :Car(name) {}
        void show()
        {
                cout << "购买了一辆奥迪:" << m_name << endl;
        }
};


enum CarType
{
        BMW,
        AUDI
};

class SimpleFactory
{
public:
        Car* createCar(CarType ct)
        {
                switch (ct)
                {
                case BMW:
                        return new Bmw("X1");
                case AUDI:
                        return new Audi("A8");
                default:
                        cerr << "传入参数不正确" << endl;
                        break;
                }
                return nullptr;
        }
};

int main()
{
        unique_ptr<SimpleFactory> factory(new SimpleFactory());
        unique_ptr<Car> p1(factory->createCar(BMW));
        unique_ptr<Car> p2(factory->createCar(AUDI));
        p1->show();
        p2->show();

        return 0;
}

工厂方法

可以弥补简单工厂方法的缺点,符合开闭原则。以本例来看,如果想生产其他的汽车,只需要添加对应的工厂类即可。

#include<iostream>
#include<memory>
using namespace std;

/*
工厂方法可以解决简单工厂模式遇到的问题
一个基类,包含一个虚工厂函数,实现多态
多个子类,重写父类的工厂函数,每个工厂负责生产一种汽车,如果想生产其他的汽车,只需要添加对应的工厂类
*/

class Car
{
public:
        Car(string name) :m_name(name) {};
        virtual void show() = 0;
protected:
        string m_name;
};

class Bmw : public Car
{
public:
        Bmw(string name) :Car(name) {}
        void show()
        {
                cout << "购买了一辆宝马:" << m_name << endl;
        }
};

class Audi : public Car
{
public:
        Audi(string name) :Car(name) {}
        void show()
        {
                cout << "购买了一辆奥迪:" << m_name << endl;
        }
};

//工厂类
class Factory
{
public:
        virtual Car* createCar(string name) = 0;
};

//宝马工厂
class BmwFty : public Factory
{
        Car* createCar(string name)
        {
                return new Bmw(name);
        }
};

//奥迪工厂
class AudiFty : public Factory
{
        Car* createCar(string name)
        {
                return new Audi(name);
        }
};

int main()
{
        unique_ptr<Factory> bmwfty(new BmwFty());
        unique_ptr<Factory> audifty(new AudiFty());
        unique_ptr<Car> p1(bmwfty->createCar("X1"));
        unique_ptr<Car> p2(audifty->createCar("A8"));
        p1->show();
        p2->show();
        return 0;
}

抽象工厂方法

一个工厂可能不止是生产汽车,也要生产相关的配件。

#include<iostream>
#include<memory>
using namespace std;

/*
一个工厂不只生产车,还会生产相关的零件
*/

//产品系列1
class Car
{
public:
        Car(string name) :m_name(name) {};
        virtual void show() = 0;
protected:
        string m_name;
};

class Bmw : public Car
{
public:
        Bmw(string name) :Car(name) {}
        void show()
        {
                cout << "购买了一辆宝马:" << m_name << endl;
        }
};

class Audi : public Car
{
public:
        Audi(string name) :Car(name) {}
        void show()
        {
                cout << "购买了一辆奥迪:" << m_name << endl;
        }
};

//系列产品2
class Light
{
public:
        virtual void show() = 0;
};

class BmwLight :public Light
{
        void show()
        {
                cout << "BMW LIght" << endl;
        }
};

class AudiLight :public Light
{
        void show()
        {
                cout << "Audi LIght" << endl;
        }
};


//工厂类 -> 抽象工厂类(对有一组关联关系的产品,提供产品对象的统一创建)
//如果新建灯也写一个类,那类太多了,太麻烦了
class AbsFactory
{
public:
        virtual Car* createCar(string name) = 0; //工厂方法 创建汽车
        virtual Light* createLight() = 0; //工厂方法 创建汽车关联的产品,车灯
};

//宝马工厂
class BmwFty : public AbsFactory
{
        Car* createCar(string name)
        {
                return new Bmw(name);
        }
        Light* createLight()
        {
                return new BmwLight();
        }
};

//奥迪工厂
class AudiFty : public AbsFactory
{
        Car* createCar(string name)
        {
                return new Audi(name);
        }
        Light* createLight()
        {
                return new AudiLight();
        }
};

int main()
{
        unique_ptr<AbsFactory> bmwfty(new BmwFty());
        unique_ptr<AbsFactory> audifty(new AudiFty());
        unique_ptr<Car> p1(bmwfty->createCar("X1"));
        unique_ptr<Car> p2(audifty->createCar("A8"));
        unique_ptr<Light> l1(bmwfty->createLight());
        unique_ptr<Light> l2(audifty->createLight());
        p1->show();
        l1->show();
        p2->show();
        l2->show();
        return 0;
}

工厂模式总结:

  1. 简单工厂:把对象的创建封装到一个接口函数里,通过传入不同的标识,返回创建的对象。客户不用自己负责 new 一个对象,不用了解对象创建的详细过程。但是不符合设计模式的开闭原则。
  2. 工厂方法:定义一个基类,提供一个纯虚函数(创建产品),定义派生类(具体产品的工厂)负责创建爱你对应的产品,可以做到不同的产品在不同的工厂里创建,能够实现对现有的工厂,以及产品的修改关闭。缺点是:实际上,很多产品都会有关联关系,不应该放在不同的工厂里去创建。
  3. 抽象工厂方法:把有关联关系的的产品放在一个抽象工厂里面AbsFactory,派生类负责创建该系列所有的产品。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1046677.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构与算法(C语言版)P7---串、数组、广义表

串、数组、广义表大体了解 我们知道前面学过的__顺序表、链表、栈、队列__&#xff0c;这些都属于线性表。 其中__栈、队列__是操作受限的线性表。 比如&#xff1a; 栈&#xff0c;先进后出&#xff0c;只能在栈顶插入和删除数据。队列&#xff1a;先进先出&#xff0c;只…

TensorFlow入门(八、TensorBoard可视化工具的应用)

TensorBoard常用函数和类http://t.csdn.cn/Hqi9c TensorBoard可视化的过程: ①确定一个整体的图表,明确从这个图表中获取哪些数据的信息 ②确定在程序的哪些节点、以什么样的方式进行汇总数据的运算,以记录信息,比如在反向传播定义以后,使用tf.summary.scalar记录损失值的变…

金蝶云星空与旺店通·企业奇门对接集成其他出库查询打通创建其他出库单

金蝶云星空与旺店通企业奇门对接集成其他出库查询打通创建其他出库单 源系统:金蝶云星空 金蝶K/3Cloud&#xff08;金蝶云星空&#xff09;是移动互联网时代的新型ERP&#xff0c;是基于WEB2.0与云技术的新时代企业管理服务平台。金蝶K/3Cloud围绕着“生态、人人、体验”&#…

CTF_BUUCTF_Reverse解题_01earsyre

题目地址&#xff1a;BUUCTF在线评测 拿到题目解压&#xff0c;PE看哈是否加壳&#xff0c;几位的 64位&#xff0c;GCC没加壳&#xff0c;那好办了直接IDA 64淦 这不是flag就出来了吗&#xff01; 果然是easyea&#xff0c;flag&#xff1a;flag{this_Is_a_EaSyRe} CTF工具包…

传统订货方式和网上企业APP订货方式的差别|网站搭建|小程序开发

传统订货方式和网上企业APP订货方式的差别|网站搭建|小程序开发 1、管货品&#xff1a;实时关注热销和滞销商品的库存订货系统&#xff1a;采购单一键生成入库单&#xff0c;便捷的实现从采购到仓库到销售一体化的进销存管理。 传统模式&#xff1a;进销存管理难&#xff1a;…

工业物联网——定义和主要概念

工业物联网背后的理念是使用工业设施中“哑巴设备”多年来产生的数据。装配线上的智能机器不仅可以更快地捕获和分析数据&#xff0c;且在交流重要信息方面也更快&#xff0c;这有助于更快、更准确地做出业务决策。 信息技术&#xff08;IT&#xff09;和运营技术&#xff08;…

一分钟用手机搞定视频提取伴奏

上台表演需要去掉人声&#xff0c;提取伴奏&#xff0c;这个操作可以直接使用【音分轨】软件中的【视频提取伴奏】功能&#xff0c;接下来教大家具体的操作流程&#xff01; 第一步&#xff1a;在首页点击【人声分离】&#xff0c;上传需要分离的视频&#xff0c;有三种方式可以…

【python零基础入门学习】python进阶篇之高阶函数

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…

一键生成,轻松制作个性化瓜分红包活动二维码

在如今竞争激烈的市场中&#xff0c;营销活动成为各个品牌推广的重要手段。而在朋友圈这个信息交流的平台上&#xff0c;如何引起用户的关注和参与&#xff0c;成为了每个营销人员的关注焦点。而打造一个引爆朋友圈的瓜分红包活动&#xff0c;无疑是一种非常有效的方法。接下来…

Win10系统怎么把桌面路径改为其他盘?

Win10系统怎么把桌面路径改为其他盘&#xff1f;Win10系统默认将桌面文件夹路径设置在系统安装盘中&#xff0c;通常是C盘。但是&#xff0c;如果Win10电脑C盘空间不足了&#xff0c;就会影响系统的正常运行。下面小编给大家介绍在Win10系统中将桌面路径改为其他盘的详细方法。…

代码随想录算法训练营第四十一天 | 动态规划 part 3 | 343. 整数拆分、96.不同的二叉搜索树

目录 343. 整数拆分思路代码 96.不同的二叉搜索树思路代码 343. 整数拆分 Leetcode 思路 dp[i] 表示 分拆数字i&#xff0c;可以得到的最大乘积为dp[i]。dp[i] max(dp[i], max((i - j) * j, dp[i - j] * j)) 贪心解法 这里粘贴一下美版 StefanPochmann 老哥的 idea&#…

Host掌控SSD内黑匣子的历史演进

在固态硬盘&#xff08;SSD&#xff09;的世界里&#xff0c;一直有一个神秘的“黑盒子”现象。这个现象指的是主机&#xff08;Host&#xff09;对SSD的控制能力有限&#xff0c;只能通过既定的接口进行基本的读写操作。但随着技术的不断发展&#xff0c;这个“黑盒子”正在被…

Day-01 从 0 开始搭建一套规范的 Vue3.x 项目工程环境

一、架构搭建 请确保你的电脑上成功安装 Node.js&#xff0c;本项目使用 Vite 构建工具&#xff01; 查看 Node.js 版本&#xff1a; ps&#xff1a; 需要注意的是vite需要你的node的版本在12以上 node -v // v16.20.1 建议将 Node.js 升级到最新的稳定版本&#xff1a;…

基于Laravel 5.6的运动健身类小程序前后端源码

基于Laravel 5.6的运动健身、健康类小程序前后端源码&#xff0c;一套比较基础的运动健康、健身类小程序源码。朋友自己无聊写的&#xff0c;比较基础&#xff0c;有需要的可以拿去修修改改升级开发一下。 使用宝塔安装&#xff0c;比较省事&#xff0c;PHP相关的扩展需要启用…

车载高速CAN(HighSpeed CAN)通信之CAN Bus Off

本文主要以普及CAN通信基本原理为目的&#xff0c;如有从事相关领域或者有意从事车载嵌入式开发的读友们欢迎留言探讨。 本文含有关键字如下。 CAN Bus Off&#xff0c;Bus Off DTC&#xff0c;Bus Off Recovery CAN Bus Off 连接到CAN网络的通信设备一般称为节点&#xff…

信息安全:恶意代码防范技术原理.

信息安全&#xff1a;恶意代码防范技术原理. 恶意代码的英文是 Malicious Code, 它是一种违背目标系统安全策略的程序代码&#xff0c;会造成目标系统信息泄露、资源滥用&#xff0c;破坏系统的完整性及可用性。 目录&#xff1a; 恶意代码概述&#xff1a; &#xff08;1&a…

mac openssl 版本到底怎么回事 已解决

在mac 安装node多版本的时候&#xff0c;有可能把原有的 openssl1.1 版本 直接要再一次升级了&#xff0c;无奈的 php环境 编译器是 openssl 1.1 还是 3.0 &#xff0c;今天来个底朝天的找问题。 brew search openssl 有安装 三个版本。 但是错误提示 是第二个版本。 brew …

知识分享 钡铼网关功能介绍:使用SSLTLS 加密,保证MQTT通信安全

背景 为了使不同的设备或系统能够相互通信&#xff0c;让旧有系统和新的系统可以集成&#xff0c;通信更加灵活和可靠。以及将数据从不同的来源收集并传输到不同的目的地&#xff0c;实现数据的集中管理和分发。 通信网关完美克服了这一难题&#xff0c;485或者网口的设备能通过…

在 Esp32 摄像头上实现边缘脉冲 FOMO 物体检测

轻松在 Esp32 相机上运行边缘脉冲 FOMO 物体检测的世界最佳指南。即使您是初学者 介绍 对象检测是检测图像内感兴趣的对象的任务。直到几年前,由于模型的复杂性和要执行的数学运算的数量惊人,这项任务还需要强大的计算机来完成。 然而,由于像Edge Impulse这样的平台,初学者…

css中常用单位辨析

辨析 px&#xff1a;像素&#xff1b;css中最普遍最常用的单位&#xff0c;不管在何种设备或分辨率上&#xff0c;1px始终代表屏幕上的一个像素。 %&#xff1a;百分比&#xff1b;基于父元素相对属性的百分比。 em&#xff1a;当前字体大小的倍数&#xff1b;基于父元素字体…