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

这篇具有很好参考价值的文章主要介绍了结构型设计模式-单例模式/工厂模式/抽象工厂。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

设计模式专栏目录

创建型设计模式-单例模式/工厂模式/抽象工厂
行为型设计模式:模板设计模式/观察者设计模式/策略设计模式
C#反射机制实现开闭原则的简单工厂模式

设计模式分类

设计模式可以分为三种类型:创建型设计模式、结构型设计模式和行为型设计模式

创建型设计模式:这些模式涉及到对象的创建机制,包括简单工厂模式、工厂方法模式、抽象工厂模式、单例模式、建造者模式和原型模式。

结构型设计模式:这些模式涉及到类和对象的组合,包括适配器模式、桥接模式、组合模式、装饰器模式、外观模式、享元模式和代理模式。

行为型设计模式:这些模式涉及到对象之间的通信和交互,包括责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。

本文是对创建型设计模式中的单例、工厂模式的一个总结。

单例模式

定义

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

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

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的话需要在外层加锁,影响效率。

为何要用到静态成员?

当我们正常书写一个类,我们可以通过这个类创建出很多对象,这显然是不符合单例模式规则的。无论我们是在栈上还是堆区创建对象,都会调用构造函数,如果将构造函数私有化,类外就不能创建对象了。但是随之带来了新的问题,现在的类一个对象都创建不了了。

而静态成员变量可以通过类名的方式访问到,不一定通过创建对象。所以我们在类内public作用域下声明一个静态成员变量,类外是可以访问到的。而且静态成员变量是共享的,才符合单例设计模式。

工厂模式

开闭原则

开闭原则,在面向对象编程领域中,规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”,这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。

定义

工厂模式中实例的创建是通过封装了的工厂方法实现的,而不是常见的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文章来源地址https://www.toymoban.com/news/detail-506078.html

到了这里,关于结构型设计模式-单例模式/工厂模式/抽象工厂的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 结构型设计模式——外观模式

    有句话说这个世界就是个草台班子,只不过排面做的好看而已,里面都是一包糠。这句话来形容外观模式非常准确,外观模式又叫门面模式,顾名思义一个系统我不管你里面有多复杂有多少屎山代码,我只要求你提供的接口好用,简单就行,即门面要有排面!用专业的话讲是

    2024年01月22日
    浏览(45)
  • 结构型设计模式——桥接模式

    桥接模式(Bridge pattern): 使用桥接模式通过将实现和抽象放在两个不同的类层次中而使它们可以独立改变。 桥接模式 (Bridge) 是一种结构型设计模式, 可将 抽象 部分与 实现 部分 分离 ,使它们都可以独立的变化。如果一个系统需要在构件的抽象化角色和具体化角色之间增加更

    2024年02月07日
    浏览(48)
  • 设计模式—结构型模式之代理模式

    代理模式(Proxy Pattern) ,给某一个对象提供一个代理,并由代理对象控制对原对象的引用,对象结构型模式。 比如我们有一个直播平台,提供了直播功能,但是如果不进行美颜,可能就比较冷清。所以美颜功能就是我们的增强,可以用静态代理来实现。 直播接口: 直播类: 如果

    2024年02月05日
    浏览(57)
  • 设计模式-结构型模式之桥接模式

    设想如果要绘制矩形、圆形、椭圆、正方形,我们至少需要4个形状类,但是如果绘制的图形需要具有不同的颜色,如红色、绿色、蓝色等,此时至少有如下两种设计方案: 第一种设计方案是为每一种形状都提供一套各种颜色的版本。 第二种设计方案是根据实际需要对形状和

    2023年04月18日
    浏览(41)
  • 设计模式—结构型模式之桥接模式

    将抽象与实现解耦,使两者都可以独立变化。 在现实生活中,某些类具有两个或多个维度的变化,如图形既可按形状分,又可按颜色分。如何设计类似于 Photoshop 这样的软件,能画不同形状和不同颜色的图形呢?如果用继承方式,m 种形状和 n 种颜色的图形就有 m×n 种,不但

    2024年02月05日
    浏览(49)
  • 设计模式之桥接模式【结构型模式】

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您: 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持,想组团高效学习… 想写博

    2024年01月25日
    浏览(49)
  • 设计模式之结构型模式---代理模式

    代理模式是一种结构型设计模式,它为目标对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用,客户端通过代理类与目标对象进行交互,而不是直接与目标对象进行交互。 代理模式的应用场景非常广泛,包括但不限于以下几种情

    2024年04月17日
    浏览(41)
  • 设计模式【结构型】-- 装饰者模式

    装饰者模式是一种 结构型设计模式 ,它允许你动态地将新功能添加到对象中,通过将对象放入包含这些功能的特殊包装器对象中。这样一来,你可以在运行时通过组合不同的对象来扩展功能,而不是通过继承修改代码。 大白话 : 装饰模式,是指在不改变原有对象的基础上

    2024年02月16日
    浏览(56)
  • 设计模式结构型——享元模式

    目录 什么是享元模式 享元模式的实现 享元模式角色 享元模式类图 享元模式代码实现 享元模式的特点 优点 缺点 使用场景 注意事项         享元模式(Flyweight Pattern)是一种结构型设计模式,享元模式中的“享元”指被共享的单元,享元模式通过复用对象,以达到节省

    2024年02月16日
    浏览(46)
  • 结构型设计模式之代理模式【设计模式系列】

    C++技能系列 Linux通信架构系列 C++高性能优化编程系列 深入理解软件架构设计系列 高级C++并发线程编程 设计模式系列 期待你的关注哦!!! 现在的一切都是为将来的梦想编织翅膀,让梦想在现实中展翅高飞。 Now everything is for the future of dream weaving wings, let the dream fly in reali

    2024年02月16日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包