结构型设计模式-单例模式/工厂模式/抽象工厂

news/2024/11/18 18:49:28/

单例模式

定义

保证一个类仅有一个实例,并提供一个该实例的全局访问点。

示例:(懒汉模式-非线程安全)

class Singleton {
public:static Singleton * GetInstance() {if (_instance == nullptr) {_instance = new Singleton();}return _instance;}
private:Singleton(){}; //构造~Singleton(){};Singleton(const Singleton &) = delete; //拷⻉	构造Singleton& operator=(const Singleton&) = delete;//拷贝赋值构造Singleton(Singleton &&) = delete;//移动构造Singleton& operator=(Singleton &&) = delete;//移动拷贝构造static Singleton * _instance;
};
Singleton* Singleton::_instance = nullptr;//静态成员需要初始化

懒汉模式与饿汉模式

直观区别:饿汉:饿汉就是类一旦加载,就把单例初始化完成,保证getInstance的时候,单例是已经存在了。懒汉:懒汉比较懒,只有当调用getInstance的时候,才回去初始化这个单例。

从性能线程上的区别
1、线程安全:饿汉式天生就是线程安全的,可以直接用于多线程而不会出现问题。懒汉式本身是非线程安全的。
2、资源加载和性能:饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内 存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成。

而懒汉式顾名思义,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,第一次调用时要做初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样了。

如果这个创建过程很耗时,比如需要连接10000次数据库(夸张了…😃),并且这个类还并不一定会被使用,那么这个创建过程就是无用的。这样的话可能懒汉模式更适合。

饿汉模式示例

#include <iostream>
using namespace std;
class Singleton
{
public:static Singleton* instance = new Singleton();//提前实例化static Singleton* GetInstance() {return instance;}
private:Singleton(){}; //构造~Singleton(){};Singleton(const Singleton &) = delete; //拷⻉  构造Singleton& operator=(const Singleton&) =delete;//拷贝赋值构造Singleton(Singleton &&) = delete;//移动构造Singleton& operator=(Singleton &&) =delete;//移动拷贝构造
};
int main() {Singleton* test1 = Singleton::GetInstance();cout << test1 << endl;Singleton* test2 = Singleton::GetInstance();cout << test2 << endl;return 0;
}

懒汉模式-线程安全

#include <mutex>
class Singleton { // 懒汉模式 lazy load
public:
static Singleton * GetInstance() {
//在外面加锁会造成锁资源浪费,,每次调用都会调用锁。
//我们其实只需要第一次调用的时候才需要锁,其他时候是不需要的
if (_instance == nullptr) {std::lock_guard<std::mutex> lock(_mutex); // 双重检测可以避免第一次读的时候多个线程进入的问题。if (_instance == nullptr) {_instance = new Singleton();}
}return _instance;
}
private:
static void Destructor() {if (nullptr != _instance) {delete _instance;_instance = nullptr;}
}
Singleton(){}; //构造
~Singleton(){};
Singleton(const Singleton &) = delete; //拷⻉构造
Singleton& operator=(const Singleton&) = delete;//拷贝赋值构造
Singleton(Singleton &&) = delete;//移动构造
Singleton& operator=(Singleton &&) = delete;//移动拷贝构造
static Singleton * _instance;
static std::mutex _mutex;
};
Singleton* Singleton::_instance = nullptr;//静态成员需要初始化
std::mutex Singleton::_mutex; //互斥锁初始化
  • 双重if判断可以节约资源。不用双重if的话需要在外层加锁,影响效率。

工厂模式

定义

工厂模式中实例的创建是通过封装了的工厂方法实现的,而不是常见的new操作来实现的。在工厂模式中,我们创建对象时不会对上层暴露创建逻辑,而是通过使用一个共同结构来指向新创建的对象。

简单工厂模式

每类产品需要有一个虚基类,通过接收类别参数生产具体的产品。

#include <iostream>
enum ProductType
{PRODUCT_A,PRODUCT_B
};
// 产品基类
class Product
{
public:virtual void Show() = 0;
};// 产品 A
class ProductA : public Product
{
public:void Show(){std::cout << "Product A." << std::endl;}
};// 产品 B
class ProductB : public Product
{
public:void Show(){std::cout << "Porduct B." << std::endl;}
};// 工厂
class Factory
{
public:Product* Create(int type){switch(type){case PRODUCT_A : return new ProductA; break;case PRODUCT_B : return new ProductB; break;default : break;}}
};
int main()
{Factory *factory = new Factory();factory->Create(PRODUCT_A)->Show();factory->Create(PRODUCT_B)->Show();return 0;
}

缺点:简单工厂模式将所有的创建逻辑集中在一个工厂类中。因此需要增加新的类型产品的话,除了增加继承类,还需要修改Factory类中的内容,违背了开闭原则。

工厂方法模式

与简单工厂类相比,通过虚基工厂类来添加新的类型产品。

#include <iostream>// 产品基类
class Product
{
public:virtual void Show() = 0;
};// 工厂基类
class Factory
{
public:virtual Product* Create() = 0;
};// 产品 A
class ProductA : public Product
{
public:void Show(){std::cout << "Product A." << std::endl;}
};// 产品 B
class ProductB : public Product
{
public:void Show(){std::cout << "Porduct B." << std::endl;}
};// 工厂 A
class FactoryA : public Factory
{
public:Product* Create(){return new ProductA;}
};// 工厂 B
class FactoryB : public Factory
{
public:Product* Create(){return new ProductB;}
};int main()
{FactoryA *factoryA = new FactoryA();FactoryB *factoryB = new FactoryB();factoryA->Create()->Show();factoryB->Create()->Show();return 0;
}

需要新增类型产品时,新增我们的产品继承类,和工厂继承类就行了,符合开闭原则。

缺点:每类产品都需要新建一个工厂类。导致系统过大。

抽象工厂模式

相对于工厂方法模式中需要每类产品都需要新建一个工厂类,抽象工厂模式,是把几类产品组成一个产品组,并在一个工厂类中去做这个产品组中所有产品的构建动作。

#include <iostream>// Product A
class ProductA
{
public:virtual void Show() = 0;
};class ProductA1 : public ProductA
{
public:void Show(){std::cout << "Product A1." << std::endl ;}
};class ProductA2 : public ProductA
{
public:void Show(){std::cout << "Product A2." << std::endl ;}
};// Product B
class ProductB
{
public:virtual void Show() = 0;
};class ProductB1 : public ProductB
{
public:void Show(){std::cout << "Product B1." << std::endl ;}
};class ProductB2 : public ProductB
{
public:void Show(){std::cout << "Product B2." << std::endl ;}
};// Factory
class Factory
{
public:virtual ProductA* CreateProductA() = 0;virtual ProductB* CreateProductB() = 0;
};class Factory1 : public Factory
{
public:ProductA* CreateProductA(){return new ProductA1();}ProductB* CreateProductB(){return new ProductB1();}
};class Factory2 : public Factory
{ProductA* CreateProductA(){return new ProductA2();}ProductB* CreateProductB(){return new ProductB2();}
};int main()
{Factory  *factoryObj1  = new Factory1();ProductA *productObjA1 = factoryObj1->CreateProductA();ProductB *productObjB1 = factoryObj1->CreateProductB();productObjA1->Show();productObjB1->Show();Factory  *factoryObj2  = new Factory2();ProductA *productObjA2 = factoryObj2->CreateProductA();ProductB *productObjB2 = factoryObj2->CreateProductB();productObjA2->Show();productObjB2->Show();return 0;
}

缺点:如果要改我们产品组的结构的话,就需要修改我们的工厂类,这一方面就不符合开闭原则了。但在实际业务中,要避免已经确定的产品组不要再改变。

工厂模式的退化过程

当抽象工厂模式中每一个具体工厂类只创建一个产品对象,抽象工厂模式退化成工厂方法模式;当工厂方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品对象,并将创建对象的工厂方法设计为静态方法时(非虚类),工厂方法模式退化成简单工厂模式。

参考:工厂模式(C++编码)https://www.cnblogs.com/horacle/p/15494358.html


http://www.ppmy.cn/news/504287.html

相关文章

【Spring面试全家桶】Spring之6.0核心新特性介绍

文章目录 1. WebFlux2. Reactive Spring Data3. Spring Native4. Spring WebSocket支持5. Kotlin扩展支持6. JUnit5支持7.实战中Spring之6.0核心新特性的问题与解决方案 Spring 6.0是目前最新的Spring版本&#xff0c;其中包含了许多新特性和改进。以下是Spring 6.0核心新特性的…

8年测试老鸟整理,接口自动化测试mock总结,这些你会多少?

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Mock原理/实现机制…

Java线程的六种状态(付代码解释)

目录 一.新建状态 (New) 解释 代码 运行结果 ​编辑 二.运行状态(Runnable) 解释 代码 运行结果 三.等待状态&#xff08;Waiting&#xff09; 解释 代码 运行结果 四.阻塞状态&#xff08;Blocked&#xff09; 解释 代码 运行结果 五.计时等待状态&#xff08;…

什么是元宇宙?元宇宙由哪些关键技术、设备构成?

元宇宙近几年来火爆起来,各个行业争先恐后加入。从目前来看,元宇宙初步体现在游戏娱乐行业、社交、消费、数字孪生等方面。元宇宙近两年开始在各个行业快速崛起,但各个行业并没有一个清晰的发展方向,那么什么是元宇宙? 元宇宙到底由哪些技术和设备组成&#xff1f;查询了很多资…

邮件打开率低?来看看这几招提高邮件打开率!

什么是邮件打开率&#xff1f; 邮件打开率&#xff1a;简单来讲就是收件人打开的邮件数占发送邮件总数的百分比。 我们要做的就是如何吸引收件人打开邮件&#xff0c;那可以从以下几个方面来考虑&#xff1a; 1、邮件标题 邮件标题直接向收件人表达了这封邮件是关于什么的&am…

笔记本电脑禁用集显会变卡?

前因&#xff1a;  前些天由于win11更新出来的漏洞桌面窗口管理器内存溢出&#xff0c;原因因为好像集显驱动有问题&#xff0c;于是乎我禁用了集显&#xff0c;只使用独显。结果打开office会变的很卡&#xff0c;而且搜狗打字也会变得很卡。 原因&#xff1a; 搜了一圈&…

笔记本电脑无线被禁用 是哪个服务器,笔记本无线网络被禁用怎么打开?|无线网络被禁用打开方法...

使用笔记本&#xff0c;最方便的当然是连接无线网络来上网&#xff0c;而不是使用本地连接&#xff0c;但是有使用win7系统的用户遇到了笔记本无线网络被禁用的问题&#xff0c;自己又不知道怎么打开&#xff0c;所以PE吧就给大家带来了笔记本无线网络被禁用打开的方法。 如果只…

计算机网络点了禁用,win10电脑以太网禁用开启不了的修复办法

以太网是局域网的一种&#xff0c;传播距离不远&#xff0c;但网速很快&#xff0c;虽然适合现代办公。我们都知道开启以太网才能正常连接网络。有些win10纯净版的用户反映说明明网络正常&#xff0c;手机都可以上网&#xff0c;工作的电脑却无法连接网络&#xff0c;发现以太网…