设计模式总结(一)

简介: 设计模式总结(一)

面对对象中有哪些设计原则

开闭原则

里氏替换原则

迪米特原则

依赖导致原则


** 举例解释**

自动驾驶系统公司是高层,汽车生产厂商为低层,它们不应该互相依赖,一方变动另一方也会跟着变动;而应该抽象一个自动驾驶行业标准,高层和低层都依赖它;这样以来就解耦了两方的变动;自动驾驶系统、汽车生产厂商都是具体实现,它们应该都依赖自动驾驶行业标准(抽象)。

多线程环境下单例模式

单例单线程模式

  • 保证一个类仅有一个实例:使用静态成员变量形式来实现。
  • 提供该实例的全局访问点:使用静态的成员函数来实现。
  • 保证申请在堆区的Singleton()能够被释合理的释放掉:使用c++中的库函数atextit()atexit函数详解参考。并需手动实现析构函数。
  • 为了实现只能通过GetInstance()函数来实现对象的创建需要对外屏蔽构造函数、赋值操作、拷贝构造函数。
  • 静态成员函数只能访问静态成员变量和静态成员函数。
  • 静态成员函数没有this指针,不能调用成员函数,可参考static、const关键字
//Singleton
#include <iostream>
class Singleton {
public:
  static Singleton* GetInstance() {
    if (_instance == nullptr) {
      _instance = new Singleton();
      std::atexit(Destructor);  //登记函数  
    }
    return _instance;
  }
private:
  static void Destructor() {  //实现析构
    if (_instance != nullptr) {
      delete _instance;
      _instance = nullptr;
    }
  }
  Singleton() {};
  ~Singleton() {};  
  Singleton(const Singleton &clone) {};  //拷贝构造函数
  Singleton &operator= (const Singleton &) {};  //赋值操作
  static Singleton *_instance;  //一个类只有一个实例
};
Singleton* Singleton::_instance = nullptr;  //静态变量,类内声明类外初始化

多线程环境下单例模式—只加锁

  • 加锁只保证了临界资源只有一个线程访问。
//Singleton_thread 加锁
#include <iostream>
#include <mutex>
class Singleton {
public:
  static Singleton* GetInstance() {
    //std::lock_guard<std::mutex> lock(_mutex);  //该位置锁的力度过大
    if (_instance == nullptr) {  //第一次_instance没有值
      std::lock_guard<std::mutex> lock(_mutex);
      if (_instance == nullptr) {  //其他情况下_instance有值
        _instance = new Singleton();  //多线程环境下编译器和CPU会对程序进行优化
        std::atexit(Destructor);
      } 
    }
    return _instance;
  }
private:
  static void Destructor() {  //实现析构
    if (_instance != nullptr) {
      delete _instance;
      _instance = nullptr;
    }
  }
  Singleton() {};
  ~Singleton() {};  
  Singleton(const Singleton &clone) {};  //拷贝构造函数
  Singleton &operator= (const Singleton &) {};  //赋值操作
  static Singleton *_instance;
  static std::mutex _mutex;
};
Singleton* Singleton::_instance = nullptr;  //静态变量,类内声明类外初始化
std::mutex Singleton::_mutex;

多线程环境下单例模式—加锁+原子操作

  • 多线程环境下编译器会对程序进行优化,导致指令执行顺序发生变化。
  • new 操作符执行了哪些操作:
    1) 分配内存;
    2)调用构造函数 (比较耗时);

3)返回指针,赋值运算符。

编译器优化后执行顺序可能为:1 3 2。就会出现内存还没有进行构造就进行了返回。即_instance 不为空,但是_instaned没有经过构造函数初始化其内存,当使用到的时候就会出现错误。利用原子变量来避免这个现象。

//Singleton_atomic
#include <iostream>
#include <mutex>
#include <atomic>
class Singleton {
public:
  static Singleton* GetInstance() {
    Singleton* tmp = _instance.load(std::memory_order_relaxed);  //保证tmp原子性
    std::atomic_thread_fence(std::memory_order_acquire);  //内存屏障,不让tmp优化到下面
    //std::lock_guard<std::mutex> lock(_mutex);  //该位置锁的力度过大
    if (tmp == nullptr) {  //第一次_instance没有值
      std::lock_guard<std::mutex> lock(_mutex);
      tmp = _instance.load(std::memory_order_relaxed);
      if (tmp == nullptr) {  //其他情况下_instance有值
        tmp = new Singleton();  //多线程环境下编译器和CPU会对程序进行优化
        std::atomic_thread_fence(std::memory_order_release);  //不让store优化到上面去
        _instance.store(tmp, std::memory_order_relaxed);  //将tmp写回原子变量_instance中
        std::atexit(Destructor);
      } 
    }
    return tmp;
  }
private:
  static void Destructor() {  //实现析构
    Singleton* tmp = _instance.load(std::memory_order_relaxed);
    if (tmp != nullptr) {
      delete _instance;
      tmp = nullptr;
      _instance.store(tmp, std::memory_order_relaxed);
    }
  }
  Singleton() {};
  ~Singleton() {};  
  Singleton(const Singleton &clone) {};  //拷贝构造函数
  Singleton &operator= (const Singleton &) {};  //赋值操作
  static std::atomic<Singleton*> _instance;
  static std::mutex _mutex;
};
std::atomic<Singleton*> Singleton::_instance;  //静态变量,类内声明类外初始化
std::mutex Singleton::_mutex;

工厂模式

工厂模式

// 实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式txt 后面可能扩展excel格式csv

//factory
#include <string>
// 实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式txt 后面可能扩展excel格式csv
class IExport {
public:
    virtual bool Export(const std::string &data) = 0;
    virtual ~IExport(){}
};
class ExportXml : public IExport {
public:
    virtual bool Export(const std::string &data) {
        return true;
    }
};
class ExportJson : public IExport {
public:
    virtual bool Export(const std::string &data) {
        return true;
    }
};
class ExportTxt : public IExport {
public:
    virtual bool Export(const std::string &data) {
        return true;
    }
};
class ExportCSV : public IExport {
public:
    virtual bool Export(const std::string &data) {
        return true;
    }
};
class IExportFactory {
public:
    IExportFactory() {
        _export = nullptr;
    }
    virtual ~IExportFactory() {
        if (_export) {
            delete _export;
            _export = nullptr;
        }
    }
    bool Export(const std::string &data) {
        if (_export == nullptr) {
            _export = NewExport();
        }
        return _export->Export(data);
    }
protected:
    virtual IExport * NewExport(/* ... */) = 0;
private:
    IExport* _export;
};
class ExportXmlFactory : public IExportFactory {
protected:
    virtual IExport * NewExport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IExport * temp = new ExportXml();
        // 可能之后有什么操作
        return temp;
    }
};
class ExportJsonFactory : public IExportFactory {
protected:
    virtual IExport * NewExport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IExport * temp = new ExportJson;
        // 可能之后有什么操作
        return temp;
    }
};
class ExportTxtFactory : public IExportFactory {
protected:
    IExport * NewExport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IExport * temp = new ExportTxt;
        // 可能之后有什么操作
        return temp;
    }
};
class ExportCSVFactory : public IExportFactory {
protected:
    virtual IExport * NewExport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IExport * temp = new ExportCSV;
        // 可能之后有什么操作
        return temp;
    }
};
int main () {
    IExportFactory *factory = new ExportTxtFactory();
    factory->Export("hello world");
    return 0;
}

抽象工厂

导出功能(IExport )、导入功能(IImport),同一个格式的导入和导出是相关联的,我们通过一个接口去封装这个关联性,这里用IDataApiFactory来实现。

#include <string>
// 实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式txt 后面可能扩展excel格式csv
class IExport {
public:
    virtual bool Export(const std::string &data) = 0;
    virtual ~IExport(){}
};
class ExportXml : public IExport {
public:
    virtual bool Export(const std::string &data) {
        return true;
    }
};
class ExportJson : public IExport {
public:
    virtual bool Export(const std::string &data) {
        return true;
    }
};
class ExportTxt : public IExport {
public:
    virtual bool Export(const std::string &data) {
        return true;
    }
};
class ExportCSV : public IExport {
public:
    virtual bool Export(const std::string &data) {
        return true;
    }
};
class IImport {
public:
    virtual bool Import(const std::string &data) = 0;
    virtual ~IImport(){}
};
class ImportXml : public IImport {
public:
    virtual bool Import(const std::string &data) {
        return true;
    }
};
class ImportJson : public IImport {
public:
    virtual bool Import(const std::string &data) {
        return true;
    }
};
class ImportTxt : public IImport {
public:
    virtual bool Import(const std::string &data) {
        return true;
    }
};
class ImportCSV : public IImport {
public:
    virtual bool Import(const std::string &data) {
        // ....
        return true;
    }
};
class IDataApiFactory {
public:
    IDataApiFactory() {
        _export = nullptr;
        _import = nullptr;
    }
    virtual ~IDataApiFactory() {
        if (_export) {
            delete _export;
            _export = nullptr;
        }
        if (_import) {
            delete _import;
            _import = nullptr;
        }
    }
    bool Export(const std::string &data) {
        if (_export == nullptr) {
            _export = NewExport();
        }
        return _export->Export(data);
    }
    bool Import(const std::string &data) {
        if (_import == nullptr) {
            _import = NewImport();
        }
        return _import->Import(data);
    }
protected:
    virtual IExport * NewExport(/* ... */) = 0;
    virtual IImport * NewImport(/* ... */) = 0;
private:
    IExport *_export;
    IImport *_import;
};
class XmlApiFactory : public IDataApiFactory {
protected:
    virtual IExport * NewExport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IExport * temp = new ExportXml;
        // 可能之后有什么操作
        return temp;
    }
    virtual IImport * NewImport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IImport * temp = new ImportXml;
        // 可能之后有什么操作
        return temp;
    }
};
class JsonApiFactory : public IDataApiFactory {
protected:
    virtual IExport * NewExport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IExport * temp = new ExportJson;
        // 可能之后有什么操作
        return temp;
    }
    virtual IImport * NewImport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IImport * temp = new ImportJson;
        // 可能之后有什么操作
        return temp;
    }
};
class TxtApiFactory : public IDataApiFactory {
protected:
    virtual IExport * NewExport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IExport * temp = new ExportTxt;
        // 可能之后有什么操作
        return temp;
    }
    virtual IImport * NewImport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IImport * temp = new ImportTxt;
        // 可能之后有什么操作
        return temp;
    }
};
class CSVApiFactory : public IDataApiFactory {
protected:
    virtual IExport * NewExport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IExport * temp = new ExportCSV;
        // 可能之后有什么操作
        return temp;
    }
    virtual IImport * NewImport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IImport * temp = new ImportCSV;
        // 可能之后有什么操作
        return temp;
    }
};
int main () {
    IDataApiFactory *factory = new CSVApiFactory();
    factory->Import("hello world");
    factory->Export("hello world");
    return 0;
}

直通通道:设计模式总结(二)

充电站

推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习


相关文章
|
关系型数据库 MySQL 网络安全
MySQL主从复制之多主多从部署流程—2023.04
MySQL主从复制之多主多从部署流程—2023.04
1068 0
|
8月前
|
机器学习/深度学习 人工智能 编解码
AI视频生成也能自动补全!Wan2.1 FLF2V:阿里通义开源14B视频生成模型,用首尾两帧生成过渡动画
万相首尾帧模型是阿里通义开源的14B参数规模视频生成模型,基于DiT架构和高效视频压缩VAE,能够根据首尾帧图像自动生成5秒720p高清视频,支持多种风格变换和细节复刻。
1563 9
AI视频生成也能自动补全!Wan2.1 FLF2V:阿里通义开源14B视频生成模型,用首尾两帧生成过渡动画
|
存储 前端开发 JavaScript
微任务和宏任务有什么区别
微任务和宏任务是JavaScript异步编程中的两个概念。宏任务包括整体代码块、setTimeout等,微任务有Promise、MutationObserver等。主要区别在于执行时机:每次事件循环中,宏任务只执行一个,而微任务会在当前宏任务结束后、下一个宏任务开始前全部执行完毕。
|
9月前
|
人工智能 分布式计算 调度
打破资源边界、告别资源浪费:ACK One 多集群Spark和AI作业调度
ACK One多集群Spark作业调度,可以帮助您在不影响集群中正在运行的在线业务的前提下,打破资源边界,根据各集群实际剩余资源来进行调度,最大化您多集群中闲置资源的利用率。
|
容器
【qt】下拉列表组件
【qt】下拉列表组件
222 0
|
12月前
|
Serverless BI
有奖实践,基于EMR StarRocks实现游戏玩家画像和行为分析
阿里云EMR-StarRocks联合镜舟科技,基于EMR-StarRocks实现游戏实时湖仓分析,免费试用物化视图、Paimon写入查询等新能力,前45位赢取StarRocks定制T恤、Lamy钢笔,小米充电宝,阿里云拍拍灯等活动礼品,前500位均可获得创意马克杯。
293 7
|
编解码 开发工具 数据安全/隐私保护
如何快速实现Windows平台屏幕摄像头采集并推送RTMP|轻量级RTSP服务能力?
一个好的推送模块,除了实现高效率的编码传输外,还要有好的音视频采集机制和灵活的架构支持,便于后期功能扩展,比如实时快照、预览、实时录像等。除此之外,还要有好的交互机制(比如envent callback)、低延迟和长期运行稳定的性能。
401 0
|
C语言
【C语言】头文件命名详解 - 《铁头无敌 ! 》
头文件在C语言编程中起着组织代码和提高代码复用性的作用。标准头文件提供了丰富的库函数,而自定义头文件可以将常用函数、宏定义、类型定义等封装起来,以便在多个源文件中共享。遵循良好的头文件命名和使用约定,有助于编写清晰、易维护的C语言程序。
394 3
|
XML 文件存储 计算机视觉
【基础实操】损失函数:IoU-GIoU-DIoU-CIoU计算复现
【基础实操】损失函数:IoU-GIoU-DIoU-CIoU计算复现
342 0
【基础实操】损失函数:IoU-GIoU-DIoU-CIoU计算复现
|
人工智能 监控 数据处理
【AI大模型应用开发】【LangChain系列】6. LangChain的Callbacks模块:监控调试程序的重要手段
【AI大模型应用开发】【LangChain系列】6. LangChain的Callbacks模块:监控调试程序的重要手段
450 0