设计模式之工厂模式(C++)

简介: 设计模式之工厂模式(C++)

概述

这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
简单来说,使用了C++多态的特性,将存在继承关系的类,通过一个工厂类创建对应的子类(派生类)对象。在项目复杂的情况下,可以便于子类对象的创建。工厂
模式是我们比较常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。它是创建行模式。
工厂模式有三种:简单工厂模式、工厂方法模式和抽象工厂模式。


适用场景

  • 工厂模式的目的是为了实现解耦,将对象的创建和使用分开,即应用程序将对象的创建和初始化职责交给工厂对象。若一个对象A想要调用对象B时,如果直接通过new关键字来创建一个B实例,然后调用B实例,这样做的不好处是,当需求变更,要将B实例换成C实例时,则需要修改所有new了该实例的方法。
  • 降低代码重复。如果对象B的创建过程比较复杂,并且很多地方都用到了,那么很可能出现很多重复的代码,通过统一将创建对象B的代码放到工厂里面统一管理,可以减少代码的重复率,同时也方便维护。相比于构造函数来说,复杂的初始化,会使得构造函数非常的复杂。由于创建过程都由工厂统一的管理,有利于当业务发生变化之后的修改
  • 工厂模式将创建和使用分离,使用者不需要知道具体的创建过程,只需要使用即可。
  • 类本身有很多子类,并且经常性发生变化。
    创建对象需要大量重复的代码。
    创建对象需要访问某些信息,而这些信息不应该包含在复合类中。
    创建对象的生命周期必须集中管理,以保证在整个程序中具有一致的行为。

简单工厂模式(Simple Factory)

简单工厂模式简介

简单工厂模式 : 由 一个 工厂对象 决定 创建出 哪一种 产品类 的 实例 ;

简单工厂模式类型 : 创建型 ;

简单工厂模式的结构组成

  • 工厂类:工厂模式的核心类,会定义一个用于创建指定的具体实例对象的接口。
  • 抽象产品类:是具体产品类的继承的父类或实现的接口。
  • 具体产品类:工厂类所创建的对象就是此具体产品实例。

简单工厂模式的特点和优缺点

特点:

  • 它是一个具体的类,非接口 抽象类。有一个重要的create()方法,利用if或者 switch创建产品并返回。
  • create()方法通常是静态的,所以也称之为静态工厂。

优点:

  • 将对象的创建交给专门的工厂类负责,实现了对象的创建和对象的使用分离。
  • 提供专门的 工厂类 用于创建对象 , 客户端 无需知道所创建的产品类的类名 , 只需要知道对应产品类的参数即可创建对象实例.

缺点:

  • 工厂类职责过重,扩展性非常差,如果要增加新的产品 , 需要修改工厂类的判断逻辑,类型多时,不易维护 , 违背"开闭原则";.
  • 不支持不同的产品需要不同额外参数的情况。

简单工厂模式的适用场景

  • 创建对象少 : 工厂类 负责 创建的对象 比较少 ;
  • 不关心创建过程 : 客户端 只知道 传入 工厂类 的参数 , 对于 如何创建对象 不关心 ;

简单工厂模式的示例

功法工厂中有诸多功法、例如易筋经、神照经、小无相功、先天功等等。
每个功法各有特点,根据自身情况去选择合适自己的功法修行.

ISkill为功法的抽象类(基类),接口函数为Description(),用于描述功法特点.

YJJSkill 、SZJSkill 、XWXGSkill为具体功法的类,分别易筋经、神照经、小无相功,它们都继承于ISkill抽象类。

代码示例:

// 抽象产品类
class ISkill
{ 
public:
    virtual ~ISkill() {}
    virtual void Description() = 0; 
};
/****************************************************************************************************/
//具体产品类
// 易筋经 
class YJJSkill : public ISkill
{ 
public:
    void Description()//功法描述
    {
        std::cout << "达摩祖师所创,佛家至高绝学,练法古拙朴实,进无止境." << std::endl;
    } 
};
// 神照经 
class SZJSkill : public ISkill
{ 
public:
    void  Description()
    {
        std::cout << "极其精纯的内功,习得大乘,全身内空完全充盈,有起死回生之效" << std::endl;
    } 
};
// 小无相功 
class XWXGSkill : public ISkill
{ 
public:
    void Description()
    {
        std::cout << "逍遥派的一门内功,威力强大,不着形相,无迹可寻,只要身具此功,可以模仿别人的绝学甚至胜于原版。" << std::endl;
    }
};
/****************************************************************************************************/
//工厂类
public class SimpleSkillFactory
{
public:
   enum SKILL_TYPE
   {
      TYPE_YJ ,//易筋经
      TYPE_SZ ,//神照经
      TYPE_XW //小无相功
   };
public :
    static ISkill createSkill(int type)
     {
        switch (type) {
            case TYPE_YJ :
                return new YJJSkill();
            case TYPE_SZ :
                return new SZJSkill();
            case TYPE_XW :
                return new XWXGSkill();
             default:
               return NULL;
               break;
        }
    }
}
/****************************************************************************************************/
//目前功法工厂就提供三种功法,这里,我选择修行易筋经来筑基.
 ISkill m_Skill = SimpleSkillFactory.createSkill(SimpleSkillFactory::TYPE_YJ);
 m_Skill.Description();

工厂方法模式

工厂方法模式简介

工厂方法模式定义一个创建对象的接口,让实现这个接口的子类决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行;工厂方法模式属于创建型模式。


工厂方法模式的结构组成

  • 抽象工厂类:工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现。
  • 具体工厂类:继承于抽象工厂,实现创建对应具体产品对象的方式。
  • 抽象产品类:它是具体产品继承的父类(基类)。
  • 具体产品类:具体工厂所创建的对象,就是此类。

工厂方法模式的特点和优缺点

特点:

  • 工厂方法模式抽象出了工厂类,提供创建具体产品的接口,交由子类去实现;
  • 工厂方法模式的应用并不只是为了封装具体产品对象的创建,而是要把具体产品对象的创建放到具体工厂类实现。

优点:

  • 不关心创建细节 : 用户 只需要 关心 所需产品 对应的工厂 , 无需关心创建细节 ;
  • 符合开闭原则 : 加入 新产品 , 符合开闭原则 , 提高可扩展性 ;

缺点:

  • 增加复杂性 : 类的个数容易过多,增加系统复杂度 ;
    在添加新产品时,除了编写新的产品类之外,还要编写该产品类对应的 工厂类 ;
  • 增加难度 : 增加了系统 抽象性 和 理解难度 ;
    工厂方法本身 利用了抽象 , 该模式中会 引入抽象层 , 如果要动态创建产品类 , 还要 引入反射技术 ;
  • 一条生产线只能一个产品;

工厂方法模式的适用场景

  • 重复代码 : 创建对象 需要使用 大量重复的代码 ;
  • 不关心创建过程 : 客户端 不依赖 产品类 , 不关心 实例 如何被创建 , 实现等细节 ;
  • 创建对象 : 一个类 通过其 子类 来 指定 创建哪个对象 ;

工厂方法模式的示例

功法阁中有诸多功法、例如易筋经、神照经、小无相功、先天功等等。每个功法各有特点,根据自身的根骨去选择功法修行.

ISkillsFactory抽象工厂类,提供了创建具体功法的纯虚函数。

YJJFactorySZJFactoryXWXGFactory具体工厂类,继承持续功法类,实现对应具体功法对象的创建。


代码示例:

// 1.抽象产品类 
class ISkill
{
public:
    virtual void Description() = 0;
    virtual ~ISkill() {}
};
// 具体产品类
class YJJSkill : public ISkill
{
public:
    void Description() override
    {
        // 易筋经的描述
    }
};
class SZJSkill : public ISkill
{
public:
    void Description() override
    {
        // 神照经的描述
    }
};
class XWXGSkill : public ISkill
{
public:
    void Description() override
    {
        // 小无相功的描述
    }
};
// 2.抽象工厂类
class ISkillsFactory
{
public:
    virtual ISkill* CreateSkills() = 0;
    virtual ~ISkillsFactory() {}
};
// 3.具体工厂类
class YJJFactory : public ISkillsFactory
{
public:
    ISkill* CreateSkills() override
    {
        return new YJJSkill();
    }
};
class SZJFactory : public ISkillsFactory
{
public:
    ISkill* CreateSkills() override
    {
        return new SZJSkill();
    }
};
class XWXGFactory : public ISkillsFactory
{
public:
    ISkill* CreateSkills() override
    {
        return new XWXGSkill();
    }
};
int main()
{
    // 藏经阁某一单间专门存储易筋经经文
    YJJFactory* YJJProducer = new YJJFactory();
    // 从中取出一本易筋经
    YJJSkill* m_YJJSkill = dynamic_cast<YJJSkill*>(YJJProducer->CreateSkills());
    // 查看易筋经的描述
    m_YJJSkill->Description();
    // 释放资源
    delete YJJProducer;
    delete m_YJJSkill;
    return 0;
}

抽象工厂模式

抽象工厂模式模式简介

抽象工厂模式 : 提供 一个 创建 一系列 相关 或 相互依赖 对象 的接口 ;

创建目标对象时 , 只需要直到对象的抽象类型或接口类型即可 , 不需要知道具体的实现类型 ;

抽象工厂模式类型 : 创建型 ;


抽象工厂模式 可以将 一组具有同一主题 , 单独的工厂 封装起来 ;
在使用时 , 客户端创建抽象工厂的实现 , 使用抽象工厂作为接口 , 来创建这一主题的对象 ;
使用的时候 , 不需要知道 从内部工厂方法中获得的对象的具体类型 ;
客户端只使用这些对象的 通用接口 ;
抽象工厂模式 实现了 一组对象的 实现细节 与 使用 分离 ;


抽象工厂模式的结构组成

  • 抽象工厂类:工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现。
  • 具体工厂类:继承于抽象工厂,实现创建对应具体产品对象的方式。
  • 抽象产品类:它是具体产品继承的父类(基类)。
  • 具体产品类:具体工厂所创建的对象,就是此类。

抽象工厂模式的特点和优缺点

特点:

  • 提供一个接口,可以创建多个产品族中的产品对象。
  • 使用抽象工厂模式 , 可以在工厂变化时 , 不需要修改 客户端 使用工厂的 代码 .

优点:

  • 隔离产品代码 : 在 应用层 隔离 具体产品的代码 , 客户端 无须关心 产品创建 的细节 ;
  • 创建产品族 : 将 一个系列 的 产品族 , 统一到一起创建 ;

缺点:

  • 扩展困难 : 规定了 所有 可能 被创建 的 产品集合 , 产品族 中 扩展 新的产品 困难 , 需要 修改抽象工厂的接口 ;
  • 增加难度 : 增加了系统的 抽象性 和 理解难度 , 还要 引入反射技术;

抽象工厂模式与工厂方法模式的区别

抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;
而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。
在抽象工厂模式中,有一个产品族的概念:所谓的产品族,是指位于不同产品等级结构中功能相关联的产品组成的家族。抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品称为一个等级结构。.
如果工厂的产品全部属于同一个等级结构,则属于工厂方法模式;如果工厂的产品来自多个等级结构,则属于抽象工厂模式。


抽象工厂模式的适用场景

  • 忽略创建细节 : 客户端 不关心 产品实例 如何 被创建 , 实现等细节 ;
  • 创建产品族 : 强调 一系列 相关的 产品对象 , 一般是 同一个产品族 , 一起使用 创建对象需要大量重复的代码 ;
  • 产品类库 : 提供 一个 产品类 的库 , 所有的产品 以 同样的接口出现 , 使 客户端不依赖于具体实现 ;

当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。说的更明白一点,就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存在着一定的关联或者约束,就可以使用抽象工厂模式。
假如各个等级结构中的实现类之间不存在关联或约束,则使用多个独立的工厂来对产品进行创建,则更合适一点。
工厂方法模式适用于产品种类结构单一的场合,为一类产品提供创建的接口;
而抽象工厂方法适用于产品种类结构多的场合,主要用于创建一组(有多个种类)相关的产品,为它们提供创建的接口;就是当具有多个抽象角色时,抽象工厂便可以派上用场。


工厂方法模式的示例

功法阁中有诸多功法、例如易筋经、神照经、小无相功、先天功等等。每个功法各有特点,根据自身的根骨去选择功法修行.

ISkill抽象产品类,提供了抽象产品类纯虚函数。

ISkillsFactory抽象工厂类,提供了创建具体功法的纯虚函数。

YJJFactorySZJFactoryXWXGFactory具体工厂类,继承持续功法类,实现对应具体功法对象的创建。


代码示例:

/****************************************************************************************************/
//1. 抽象工厂类
// 功法工厂
class ISkillsFactory
{
public:
    virtual ISkill *CreateOffensiveSkill() = 0; // 创建攻击型功法
    virtual ISkill *CreateDefensiveSkill() = 0; // 创建防御型功法
    virtual ~ISkillsFactory() {}
};
/****************************************************************************************************/
// 2. 抽象产品类
class ISkill
{
public:
    virtual ~ISkill() {}
    virtual void Description() = 0; // 功法描述
    virtual void Method() = 0;       // 修行方法
};
/****************************************************************************************************/
// 3. 具体工厂类
// 易筋经和神照经存储室
class YJJ_SZJFactory : public ISkillsFactory
{
public:
    ISkill *CreateOffensiveSkill()
    {
        return new YJJSkill();
    }
    ISkill *CreateDefensiveSkill()
    {
        return new SZJSkill();
    }
};
// 小无相功和先天功存储室工厂类
class XWXG_XTGFactory : public ISkillsFactory
{
public:
    ISkill *CreateOffensiveSkill()
    {
        return new XWXGSkill();
    }
    ISkill *CreateDefensiveSkill()
    {
        return new XTGSkill();
    }
};
/****************************************************************************************************/
//神照经、小无相功和先天功这三个具体产品类
/****************************************************************************************************/
// 神照经
class SZJSkill : public ISkill
{
public:
    void Description() //功法描述
    {
        std::cout << "少林寺密传,罕见的内功绝学,运功时可感内力蓬勃,临敌可制敌于千里之外。" << std::endl;
    }
    void Method() //修行方式
    {
        std::cout << "练好神照经的关键是要熟练乾坤大挪移。" << std::endl;
    }
};
/****************************************************************************************************/
// 小无相功
class XWXGSkill : public ISkill
{
public:
    void Description() //功法描述
    {
        std::cout << "武当派王重阳所创,武学至高无上的内功心法,修行者可达至无我无相的境地。" << std::endl;
    }
    void Method() //修行方式
    {
        std::cout << "修炼小无相功需通晓无我无相之境。" << std::endl;
    }
};
/****************************************************************************************************/
// 先天功
class XTGSkill : public ISkill
{
public:
    void Description() //功法描述
    {
        std::cout << "全真教长眉真人所创,先天内功,可吸取天地日月精华,修炼出磅礴气息。" << std::endl;
    }
    void Method() //修行方式
    {
        std::cout << "修炼先天功需参透天地日月之力。" << std::endl;
    }
};
/****************************************************************************************************/
/****************************************************************************************************/
int main()
{
    // 易筋经阁包含了大量的易筋经经文
    ISkillsFactory *YJJ_SZJProducer = new YJJ_SZJFactory();
    // 从易筋经阁中取出攻击型功法易筋经
    ISkill *m_YJJSkill = YJJ_SZJProducer->CreateOffensiveSkill();
    // 查看易筋经的描述
    m_YJJSkill->Description();
    // 查看易筋经修行方式
    m_YJJSkill->Method();
    // 从易筋经阁中取出防御型功法神照经
    ISkill *m_SZJSkill = YJJ_SZJProducer->CreateDefensiveSkill();
    // 查看神照经的描述
    m_SZJSkill->Description();
    // 查看神照经修行方式
    m_SZJSkill->Method();
    // 释放资源
    delete YJJ_SZJProducer;
    delete m_YJJSkill;
    delete m_SZJSkill;
    return 0;
}

小结

为什么要使用工厂模式?

  • 统一创建对象的接口命名
  • 降低耦合度,结合多态,便于扩展,同时提高可阅读性。

面向对象的基本思想封装告诉我们,我们尽量将长的代码进行"切割",再将每一个小逻辑都"封装"起来,这样可以降低耦合度,修改的时候也可以直奔错误段落。

  • 封装创建对象时的初始化工作,使程序更规范有条理

如果使用C语言,分配并初始化的工作包括:
malloc申请内存(但申请完了对象并没有初始化,只是有了一片内存空间),并强制类型转换初始化这块内存,分配内存、类型转换、初始化等。
如果是C++,new的动作包括分配内存和调用构造函数两个步骤,比较简化了。这是对一般的初始化过程比较简单的对象。那如果初始化过程比较复杂呢?什么叫比较复杂的初始化过程呢?就是说创建对象不仅是分配内存空间,还要做一些其他初始化工作,甚至是与外部变量或者资源相关的工作。

工厂模式示例

抽象工厂类:AbstractFactory

#include <iostream>
#include <memory>
// 抽象工厂类
class AbstractFactory {
public:
    virtual ~AbstractFactory() = default;
    // 内存池工厂
    virtual std::unique_ptr<MemoryPool> createMemoryPool() = 0;
    // 线程池工厂
    virtual std::unique_ptr<ThreadPool> createThreadPool() = 0;
    // 进程池工厂
    virtual std::unique_ptr<ProcessPool> createProcessPool() = 0;
};
// 内存池抽象类
class MemoryPool {
public:
    virtual ~MemoryPool() = default;
    // ... 添加其他抽象方法
};
// 线程池抽象类
class ThreadPool {
public:
    virtual ~ThreadPool() = default;
    // ... 添加其他抽象方法
};
// 进程池抽象类
class ProcessPool {
public:
    virtual ~ProcessPool() = default;
    // ... 添加其他抽象方法
};
// 内存池工厂类
class MemoryPoolFactory : public AbstractFactory {
public:
    std::unique_ptr<MemoryPool> createTemporaryMemory() {
        // ... 创建临时内存池
    }
    std::unique_ptr<MemoryPool> createPermanentMemory() {
        // ... 创建永久内存池
    }
};
// 线程池工厂类
class ThreadPoolFactory : public AbstractFactory {
public:
    std::unique_ptr<ThreadPool> createDisposableThreadPool() {
        // ... 创建一次性线程池
    }
    std::unique_ptr<ThreadPool> createPersistentThreadPool() {
        // ... 创建长久线程池
    }
};
// 进程池工厂类
class ProcessPoolFactory : public AbstractFactory {
public:
    std::unique_ptr<ProcessPool> createSharedMemoryProcess() {
        // ... 创建带共享内存的进程池
    }
    std::unique_ptr<ProcessPool> createMessageQueueProcess() {
        // ... 创建带消息队列的进程池
    }
    std::unique_ptr<ProcessPool> createPipeProcess() {
        // ... 创建带管道的进程池
    }
};
int main() {
    // 使用工厂创建对象的示例
    MemoryPoolFactory memory_pool_factory;
    auto temporary_memory = memory_pool_factory.createTemporaryMemory();
    auto permanent_memory = memory_pool_factory.createPermanentMemory();
    ThreadPoolFactory thread_pool_factory;
    auto disposable_thread_pool = thread_pool_factory.createDisposableThreadPool();
    auto persistent_thread_pool = thread_pool_factory.createPersistentThreadPool();
    ProcessPoolFactory process_pool_factory;
    auto shared_memory_process = process_pool_factory.createSharedMemoryProcess();
    auto message_queue_process = process_pool_factory.createMessageQueueProcess();
    auto pipe_process = process_pool_factory.createPipeProcess();
    return 0;
}

具体工厂类:ProcessPool (进程池抽象类)

#include <memory>
// 抽象进程池类
class ProcessPool {
public:
    virtual ~ProcessPool() = default;
};
// 带共享内存的进程池
class SharedMemoryProcessPool : public ProcessPool {
public:
    SharedMemoryProcessPool() {
        // 初始化共享内存相关资源
        // 这里是一个示例,您可以根据实际需求初始化共享内存资源
        // 例如:创建共享内存区域,设置访问权限等
    }
    // ... 其他与共享内存进程池相关的方法,如创建进程、销毁进程、执行任务等
};
// 带消息队列的进程池
class MessageQueueProcessPool : public ProcessPool {
public:
    MessageQueueProcessPool() {
        // 初始化消息队列相关资源
        // 这里是一个示例,您可以根据实际需求初始化消息队列资源
        // 例如:创建消息队列,设置访问权限等
    }
    // ... 其他与消息队列进程池相关的方法,如创建进程、销毁进程、执行任务等
};
// 带管道的进程池
class PipeProcessPool : public ProcessPool {
public:
    PipeProcessPool() {
        // ... 初始化管道相关资源
    }
};
// 进程池工厂类
class ProcessPoolFactory : public AbstractFactory {
public:
    std::unique_ptr<ProcessPool> createSharedMemoryProcess() {
        return std::make_unique<SharedMemoryProcessPool>();
    }
    std::unique_ptr<ProcessPool> createMessageQueueProcess() {
        return std::make_unique<MessageQueueProcessPool>();
    }
    std::unique_ptr<ProcessPool> createPipeProcess() {
        return std::make_unique<PipeProcessPool>();
    }
};

在这个示例中,我们首先创建了三个具体的ProcessPool子类:SharedMemoryProcessPool、MessageQueueProcessPool和PipeProcessPool。这些子类分别表示带共享内存的进程池、带消息队列的进程池和带管道的进程池。在这些子类的构造函数中,我们可以进行各种资源的初始化操作。

接着,我们在ProcessPoolFactory类中实现了createSharedMemoryProcess、createMessageQueueProcess和createPipeProcess这三个方法。这些方法分别创建了相应类型的ProcessPool实例,并返回一个指向这些实例的unique_ptr。


具体工厂类:MemoryPool (抽象内存池类)

#include <memory>
// 抽象内存池类
class MemoryPool {
public:
    virtual ~MemoryPool() = default;
    virtual void* allocate(size_t size) = 0;
    virtual void deallocate(void* ptr) = 0;
};
// 临时内存池
class TemporaryMemoryPool : public MemoryPool {
public:
    TemporaryMemoryPool() {
        // 初始化临时内存池相关资源
        // 在此示例中,我们不需要执行任何初始化操作
    }
    // 为临时内存池分配内存
    void* allocate(size_t size) override {
        // 使用C++标准库的new操作符分配内存
        // 注意:这里可能抛出std::bad_alloc异常,需要在调用代码中处理
        return new char[size];
    }
    // 释放临时内存池的内存
    void deallocate(void* ptr) override {
        // 使用C++标准库的delete操作符释放内存
        delete[] static_cast<char*>(ptr);
    }
};
// 长久内存池
class PermanentMemoryPool : public MemoryPool {
public:
    PermanentMemoryPool() {
        // ... 初始化长久内存池相关资源
    }
    void* allocate(size_t size) override {
        // ... 为长久内存池分配内存
    }
    void deallocate(void* ptr) override {
        // ... 释放长久内存池的内存
    }
};
// 内存池工厂类
class MemoryPoolFactory : public AbstractFactory {
public:
    std::unique_ptr<MemoryPool> createTemporaryMemory() {
        return std::make_unique<TemporaryMemoryPool>();
    }
    std::unique_ptr<MemoryPool> createPermanentMemory() {
        return std::make_unique<PermanentMemoryPool>();
    }
};

在这个示例中,我们首先创建了一个MemoryPool抽象类,其中包含了两个纯虚函数:allocate和deallocate。然后,我们创建了两个具体的MemoryPool子类:TemporaryMemoryPool和PermanentMemoryPool。这些子类分别表示临时内存池和长久内存池。在这些子类中,我们实现了allocate和deallocate方法,用于分配和释放内存。

接着,我们在MemoryPoolFactory类中实现了createTemporaryMemory和createPermanentMemory方法。这些方法分别创建了相应类型的MemoryPool实例,并返回一个指向这些实例的unique_ptr。

关于使用内存池创建的不同内存类型,以下是一些建议的用途:

  1. 临时内存池(TemporaryMemoryPool):
  • 对于生命周期较短、经常创建和销毁的对象,如局部变量、临时缓冲区等。
  • 可以用于实现高效的内存管理,减少内存碎片和系统调用。
  1. 长久内存池(PermanentMemoryPool):
  • 对于生命周期较长、不经常创建和销毁的对象,如全局变量、单例对象等。
  • 可以用于减少内存分配和释放的开销,提高内存管理性能。
    使用内存池可以帮助我们更有效地管理内存资源,减少内存碎片和提高内存分配性能。为了实现这一目标,我们可以根据不同的场景和需求选择合适的内存池类型。
    例如,在一个网络服务器应用程序中,我们可能需要处理大量的短期连接。对于这种场景,我们可以使用临时内存池来管理这些短期连接的相关资源,如接收缓冲区、发送缓冲区等。这样可以避免频繁地分配和释放内存,提高性能。
    另一方面,在一个图形用户界面应用程序中,我们可能需要长时间维护一些全局状态,如主窗口、单例对象等。对于这种场景,我们可以使用长久内存池来管理这些长期存在的对象。这样可以减少内存分配的开销,提高内存管理性能。

具体工厂类:ThreadPool (抽象线程池类)

class ThreadPool {
public:
    ThreadPool(size_t num_threads) {
        for (size_t i = 0; i < num_threads; ++i) {
            threads.emplace_back([this] { worker(); });
        }
    }
    ~ThreadPool() {
        {
            std::unique_lock<std::mutex> lock(mutex);
            stop = true;
        }
        condition.notify_all();
        for (auto& thread : threads) {
            thread.join();
        }
    }
    template<typename Func, typename... Args>
    auto enqueue(Func&& func, Args&&... args) -> std::future<decltype(func(args...))> {
        using ReturnType = decltype(func(args...));
        auto task = std::make_shared<std::packaged_task<ReturnType()>>(std::bind(std::forward<Func>(func), std::forward<Args>(args)...));
        std::future<ReturnType> result = task->get_future();
        {
            std::unique_lock<std::mutex> lock(mutex);
            tasks.emplace([task] { (*task)(); });
        }
        condition.notify_one();
        return result;
    }
private:
    void worker() {
        while (true) {
            std::function<void()> task;
            {
                std::unique_lock<std::mutex> lock(mutex);
                condition.wait(lock, [this] { return stop || !tasks.empty(); });
                if (stop && tasks.empty()) {
                    break;
                }
                task = std::move(tasks.front());
                tasks.pop();
            }
            task();
        }
    }
    std::vector<std::thread> threads;
    std::queue<std::function<void()>> tasks;
    std::mutex mutex;
    std::condition_variable condition;
    bool stop = false;
};

这个线程池类可以创建一定数量的工作线程,并将任务添加到任务队列中。线程池类会自动管理线程的创建、销毁和任务的分配。通过使用线程池,我们可以避免频繁地创建和销毁线程,提高性能。

//以下是使用线程池类的示例:
ThreadPool pool(4); // 创建一个包含4个工作线程的线程池
// 添加任务到线程池
auto result1 = pool.enqueue([]() { return 1 + 2; });
auto result2 = pool.enqueue([](int a, int b) { return a * b; }, 3, 4);
// 获取任务结果
int sum = result1.get();
int product = result2.get();

调用最终的工程: main.cpp

在这个例子中,我们有一个抽象工厂AbstractFactory,它有三个具体的子类工厂:MemoryPoolFactory,ProcessPoolFactory,和ThreadPoolFactory。这些工厂分别负责创建不同类型的内存池、进程池和线程池。

int main() {
    // 创建内存池工厂
    MemoryPoolFactory memoryPoolFactory;
    // 使用工厂创建一个临时内存池
    auto temporaryMemoryPool = memoryPoolFactory.createTemporaryMemory();
    // 使用工厂创建一个持久内存池
    auto persistentMemoryPool = memoryPoolFactory.createPersistentMemory();
    // 创建进程池工厂
    ProcessPoolFactory processPoolFactory;
    // 使用工厂创建一个带共享内存的进程池
    auto sharedMemoryProcessPool = processPoolFactory.createSharedMemoryProcess();
    // 使用工厂创建一个带消息队列的进程池
    auto messageQueueProcessPool = processPoolFactory.createMessageQueueProcess();
    // 创建线程池工厂
    ThreadPoolFactory threadPoolFactory;
    // 使用工厂创建一个一次性线程池
    auto disposableThreadPool = threadPoolFactory.createDisposableThreads();
    // 使用工厂创建一个长久线程池
    auto longTermThreadPool = threadPoolFactory.createLongTermThreads();
    // ... 使用这些资源执行任务、分配内存等操作
    return 0;
}

在这个示例中,我们首先创建了一个内存池工厂、进程池工厂和线程池工厂。然后,我们分别使用这些工厂创建了临时内存池、持久内存池、带共享内存的进程池、带消息队列的进程池、一次性线程池和长久线程池。这些资源可以用于执行各种任务,例如分配内存、管理进程和线程等。通过抽象工厂模式,我们可以轻松地在不同类型的资源之间进行切换,而无需修改客户端代码。

目录
相关文章
|
1月前
|
设计模式 安全 测试技术
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
62 0
|
1月前
|
设计模式 算法 C++
【C++ 泛型编程 进阶篇】C++元模板编程与设计模式的结合应用教程(二)
【C++ 泛型编程 进阶篇】C++元模板编程与设计模式的结合应用教程
29 0
|
1月前
|
设计模式 存储 uml
C++ 设计模式实战:外观模式和访问者模式的结合使用,派生类访问基类的私有子系统
C++ 设计模式实战:外观模式和访问者模式的结合使用,派生类访问基类的私有子系统
29 1
|
6天前
|
设计模式 存储 Java
C++从入门到精通:3.5设计模式——提升代码可维护性与可扩展性的关键
C++从入门到精通:3.5设计模式——提升代码可维护性与可扩展性的关键
|
1月前
|
设计模式 算法 中间件
【C++ 可调用对象的应用】C++设计模式与现代编程技巧:深入可调用对象的世界
【C++ 可调用对象的应用】C++设计模式与现代编程技巧:深入可调用对象的世界
122 1
|
1月前
|
设计模式 机器学习/深度学习 算法
C++设计模式新篇章:掌握状态委托
C++设计模式新篇章:掌握状态委托
73 0
|
1月前
|
设计模式 算法 C++
从 C++ 优化状态机实现:结合设计模式的实用指南
从 C++ 优化状态机实现:结合设计模式的实用指南
67 1
|
1月前
|
设计模式 存储 安全
C++多线程管理的艺术:从基础到设计模式
C++多线程管理的艺术:从基础到设计模式
67 0
|
1月前
|
设计模式 缓存 编译器
【C/C++ 设计模式应用】精细化职责与灵活性:C++中的发送接口和数据转换基类设计
【C/C++ 设计模式应用】精细化职责与灵活性:C++中的发送接口和数据转换基类设计
66 0
|
1月前
|
设计模式 关系型数据库 数据库
【C++ 设计模式 工厂模式对比】深入探索设计模式:工厂方法与抽象工厂的比较与对照
【C++ 设计模式 工厂模式对比】深入探索设计模式:工厂方法与抽象工厂的比较与对照
22 1