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

C++八股--three day --设计模式之单例和工厂

对于C++编程中的思想,最常见的就是考察设计模式了
那么我们在面试中常考的设计模式包含以下几种:单例模式,
接下来我们按顺序介绍

1.单例模式:
    一个类只能创建一个实例:常应用于日志模块,数据库模块
    单例模式需要具备以下4要素
        1.构造函数私有化
        2.禁用拷贝构造,赋值重载
            类名 (const 类名 &) = delete; 禁用拷贝构造
            类名 &operator= (const 类名&)= delete; 禁用赋值构造
            上述两个方法确保构造函数只会被调用一次
        3.定义唯一对象,static:类内定义,类外初始化
        4.定义接口获取实例:【使用静态方法】原因:普通方法依赖对象,现在不存在对象
那么所需条件已经具备,那么我们可以着手写一个单例模式的示例
class Singleton{
public:
    static Singleton * getInstance()//获取唯一实例对象的接口方法
    {
        return &instance;//注意这里返回的为地址,需要用指针接收
    }
private:
    Singleton(){}
    Singleton(const Singleton&) = delete;
    Singleton &operator= (const Singleton&) = delete;
    static Singleton instance;//注意这里我定义的实例
};

Singleton Singleton::instance; //类外初始化

想必你肯定觉得上述代码很简单,只需要考虑四要素即可
在实际考察中我们还会将其结合懒汉和饿汉的设计,下面给出具体的介绍

饿汉模式下的单例模式:一定是线程安全的:在软件启动时初始化,肯定会延长软件启动时间
    还没有获取实例对象,实例对象就已经产生了。
    其实我们的上述代码就是饿汉式的

懒汉模式下的单例模式:需要注意的是我们需要的是多线程安全。
    只有获取的时候才产生实例,注意与懒汉模式的区别
//需要加锁实现互斥
std::mutex mtx; //定义锁
class Singleton{
public:
    static Singleton * getInstance()//获取唯一实例对象的接口方法
    {
        if(instance == nullptr)
        {
            lock_guard<std::mutex> guard(mtx);//加锁
            if(instance == nullptr)
            {
                instance = new Singleton();
            }
        }
        return instance;
    }
private:
    static Singleton *volatile instance;//注意这里需要使用volatile修饰,避免对该变量优化
    Singleton(){}
    Singleton(const Singleton&) = delete;
    Singleton &operator= (const Singleton&) = delete;
};

Singleton* Singleton::instance = nullptr; //类外初始化

上述做法使用锁+双重判断实现线程安全的懒汉模式,下面提供另一种模式
核心为static关键字:第一次运行的时候才初始化,note:C++11保证static定义是线程安全的
class Singleton{
public:
    static Singleton * getInstance()//获取唯一实例对象的接口方法
    {
        static Singleton instance;    
        return &instance;
    }
private:
    Singleton(){}
    Singleton(const Singleton&) = delete;
    Singleton &operator= (const Singleton&) = delete;
};

Singleton* Singleton::instance = nullptr; //类外初始化

好,上述已经成功介绍了单例模式


那么接下来为第二个设计模式
2.工厂模式
工厂模式分为三种:简单工厂(这个实际上不包含),工厂方法,抽象工厂
为什么叫工厂:主要是封装了对象的创建

下面以汽车为例
class Car
{
public:
    Car(string name) : Name(name) { }
    virtual void show() = 0;
protected:
    string Name;
};

class BaoMa :public Car
{
public:
    BaoMa(string name) : Car(name) { }
    void show(){ cout<<"get a BaoMa"<<endl; }
};

class AoDi :public Car
{
public:
    AoDi(string name) : Car(name) { }
    void show(){ cout<<"get a Aodi"<<endl; }
};

enum CarType{ baoma,aodi }; //定义枚举类型

class SimpleFactory
{
public:
    Car* createCar(CarType ct)
    {
        switch(ct)
        {
        case baoma:
            return new BaoMa("X1");
        case aodi:
            return new AoDi("A6");
        default:
            break;
        }
        return nullptr;
    }
};

上述代码封装了对象的创建,函数调用的时候只需要通过工厂调用对应的函数即可,而不需要了解内部实现
    unique_ptr<SimpleFactory> factorty(new SimpleFactory());
创建一个宝马
    unique_ptr<Car> p1(factory->createCar(BaoMa));
    p1->show();
简单工厂不好的地方:
    1.不同汽车的创建应该在不同工厂
    2.工厂应该对修改关闭

基于这样的缺点:工厂方法进行了改进
//创建工厂基类:后面各种工厂直接继承就可以了
class Factory
{
public:
    virtual Car * createCar(string name) = 0;
};
//宝马工厂
class BaoMaFactory:public Factory
{
public:
    Car * createCar(string name)
    {
        return new BaoMa(name);
    }
};

在实际上,通常有关联关系的产品系列在同一工厂,工厂方法无法实现此功能
假设我还要在工厂中生产车灯,那么就需要使用抽象工厂这一个概念
抽象工厂:对一组有关联关系的产品簇提供产品对象的统一创建
// 车灯基类
class Light
{
pubilc:
    virtual void show()=0;
};

classs BaoMaLight : public Light
{
public:
    void show(){ cout<<"get a Light"<<endl; }
};

//抽象工厂
class AbstractFactory
{
public:
    virtual Car * createCar(string name) = 0;
    virtual Light * createCarLight() = 0;
};
这些代码都比较简单,只要理解思想很容易就可以写出来,后面的代码就不再赘述了

工厂方法:提供了一个纯虚函数创建产品,定义派生类负责创建对应的产品,可以做到不同产品在不同工厂创建,实现对现有工厂和产品修改封闭

抽象工厂:把有关联关系的,属于一个产品簇的所有产品创建的接口函数,放到一个抽象工厂中


        

http://www.xdnf.cn/news/252685.html

相关文章:

  • UE运行游戏时自动播放关卡序列
  • 深度学习笔记40_中文文本分类-Pytorch实现
  • 大数据面试问答-数据湖
  • 阿里云服务器 篇五(加更):短链服务网站:添加反垃圾邮件功能
  • 多模态大语言模型arxiv论文略读(五十五)
  • Python爬虫实战:获取好大夫在线各专业全国医院排行榜数据并分析,为患者就医做参考
  • sys目录介绍
  • C++11新特性_标准库_正则表达式库
  • 数据分析_问题/优化
  • Mysql数据库之基础管理
  • 基于SpringBoot的药房药品销售管理系统
  • 深入解析C++11委托构造函数:消除冗余初始化的利器
  • Webug4.0靶场通关笔记13- 第22关越权修改密码
  • 从此,K8S入门0门槛!
  • Qt QGraphicsScene 的用法
  • openEuler 22.03 安装 Mysql 5.7,RPM 在线安装
  • C++ - 数据容器之 list(创建与初始化、元素访问、容量判断、元素遍历、添加元素、删除元素)
  • 父子组件双向绑定
  • ElasticSearch深入解析(八):索引设置、索引别名、索引模板
  • Windows配置grpc
  • 红米Note9 4G版拆开后盖操作细节
  • 51c嵌入式~电路~合集4
  • Ubuntu搭建Conda+Python开发环境
  • 【AI面试准备】Azure DevOps沙箱实验全流程详解
  • 【KWDB 创作者计划】利用KWDB解决工业物联网场景中的海量数据管理难题的思考
  • 处方流转平台权限控制模块设计(基于RBAC模型)
  • Midjourney 绘画 + AI 配音:组合玩法打造爆款短视频!
  • Notion 系列(一):页面与数据库的结构化实践
  • [Android] 网易爆米花TV 2.0.0.0429(原网易Filmly,支持多网盘的TV版、电脑版带海报墙播放器)
  • 【Java IO流】IO流详解