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

C++设计模式创建型之工厂模式整理

一、工厂模式分类

        工厂模式属于创建型模式,一般可以细分为简单工厂模式、工厂模式和抽象工厂模式。每种都有不同的特色和应用场景。

二、工厂模式详情

1、简单工厂模式

1)概述

        简单工厂模式相对来说,在四人组写的《设计模式------可复用面向对象软件的基础》中并没有提及,所以可以认为这并不算是一个标准的设计模式,但因为其场景较多,所以这里简单介绍下。有的人认为可以看做一种编程收发或者编程技巧。

2)简单工厂模式代码

class Monster
{
public:
    Monster(int life, int magic, int attack):m_life(life),m_magic(magic),m_attack(attack){}
    virtual ~Monster(){}
protected:
    int m_life;
    int m_magic;
    int m_attack;
};

class M_Undead: public Monster
{
public:
    M_Undead(int life, int magic, int attack):Monster(life, magic, attack)
    {
        cout << "一只亡灵类怪物诞生在这个世界上了" << endl;
    };
};

class M_Element: public Monster
{
public:
    M_Element(int life, int magic, int attack):Monster(life, magic, attack)
    {
        cout << "一只元素类怪物诞生在这个世界上了" << endl;
    };
};

class M_Mechanic: public Monster
{
public:
    M_Mechanic(int life, int magic, int attack):Monster(life, magic, attack)
    {
        cout << "一只机械类怪物诞生在这个世界上了" << endl;
    };
};
class CSimpleFactory
{
public:
    Monster* createMonster(eMonsterType eType)
    {
        Monster* pCreateObj = nullptr;
        if (eType == Undead_Type)
        {
            pCreateObj = new M_Undead(300, 50, 80);
        } 
        else if (eType == Element_Type)
        {
            pCreateObj = new M_Element(200, 80, 100);
        }
        else if (eType == Mechanic_Type)
        {
            pCreateObj = new M_Mechanic(400, 0, 110);
        }
        return pCreateObj;
    }
};

int main()
{

    CSimpleFactory simobj;
    Monster* pM1 = simobj.createMonster(Undead_Type);

    Monster* pM2 = simobj.createMonster(Element_Type);

    Monster* pM3 = simobj.createMonster(Mechanic_Type);

    delete pM1;
    delete pM2;
    delete pM3;
    
    return 0;
}

总结:通过工厂类来创建怪物,则意味着创建怪物时不再使用new关键字,而是通过该工厂类来进行,这样的话,即便将来拐歪种类增加,main主函数中创建怪物的代码也可以尽量保持稳定。同时也避免了在main函数中直接使用new创建对象时必须知道具体类名的情形发生,实现了创建怪物的代码与各个具体怪物类对象要实现的业务逻辑的代码隔离。当然此模式也具有明显的缺点,当引入新的怪物类型时,需要修改createMonster成员函数的源码来增加if判断分支,从而支持对新类型怪物的创建工作,这就违反了开放封闭原则。如果if分支不是很多,只有数个而并不是数十上百个,那适当违反开闭原则也可以接收的。

2、工厂模式

1)概述

        工厂模式通常也是指得是工厂方法模式,换句话说,工厂方法模式可以简称工厂模式或多态工厂模式,此种模式实现难度比简单工厂模式略高一些。需要针对每种类型的怪物都需要创建一个对应的工厂类,它通过增加新的工厂类来符合面向对象程序设计的开闭原则,但付出的代价是需要增加多个新的工厂类。

2)代码示例

class M_ParFactory
{
public:
    virtual Monster* createMonster() = 0;
    virtual ~M_ParFactory(){}
};

class M_UndeadFactory : public M_ParFactory
{
public:
    virtual Monster* createMonster()
    {
        return new M_Undead(300, 50, 80);
    }
};

class M_ElementFactory : public M_ParFactory
{
public:
    virtual Monster* createMonster()
    {
        return new M_Element(200, 80, 100);
    }
};

class M_MechanicFactory : public M_ParFactory
{
public:
    virtual Monster* createMonster()
    {
        return new M_Mechanic(400, 0, 110);
    }
};

Monster* Gbl_CreateMonster(M_ParFactory *factoryObj)
{
    return factoryObj->createMonster();
}

int main()
{
    M_ParFactory* p_ud_fy = new M_UndeadFactory();
    Monster* pM1 = Gbl_CreateMonster(p_ud_fy); //构造一只亡灵类怪物

    M_ParFactory* p_ele_fy = new M_ElementFactory();
    Monster* pM2 = Gbl_CreateMonster(p_ele_fy); //构造一只元素类怪物

    M_ParFactory* p_mec_fy = new M_MechanicFactory();
    Monster* pM3 = Gbl_CreateMonster(p_mec_fy); //构造一只机械类怪物

    //释放资源
    delete p_ud_fy;
    delete p_ele_fy;
    delete p_mec_fy;

    delete pM1;
    delete pM2;
    delete pM3;
}

总结:从上述代码中可以看到,创建怪物对象时,不需要记住具体怪物类的名称,但需要知道创建该类怪物的工厂名称。工厂模式的实现意图是定义一个用于创建对象的接口,但由子类决定要实例化的类是哪一个,该模式是的某个类的实例化延迟到子类。它当出现一个新怪物类型时,既不需要更改Gbl_CreateMonster函数,也不需要像简单工厂模式那样修改MonsterFactory类中的createMonster成员函数来增加新的if分支。

3、抽象工厂模式

1)概述

         随着业务的变化,游戏中的战斗场景数量和类型不断增加,从原来的在城镇中战斗逐步进入在沼泽战斗、在山脉地区战斗等,于是场景将重新分类,怪物分为3类,战斗场景3类,这样会产生9类怪物。如果一个工厂子类能够生产不止一种具有相同规则的怪物对象,那么就可以有效地减少所创建的工厂子类数量,这就是抽象工厂模式的核心思想。抽象工厂模式是按照产品族来生产产品,一个地点有一个工厂,该工厂负责生产本地的所有产品。

2)代码示例

//沼泽类怪物
class M_Undead_Swamp : public Monster
{
public:
    M_Undead_Swamp(int life, int magic, int attack):Monster(life, magic, attack)
    {
        cout << "一只沼泽的亡灵类怪物诞生在这个世界上了" << endl;
    };
};

class M_Element_Swamp : public Monster
{
public:
    M_Element_Swamp(int life, int magic, int attack):Monster(life, magic, attack)
    {
        cout << "一只沼泽的元素类怪物诞生在这个世界上了" << endl;
    };
};

class M_Mechanic_Swamp : public Monster
{
public:
    M_Mechanic_Swamp(int life, int magic, int attack):Monster(life, magic, attack)
    {
        cout << "一只沼泽的机械类怪物诞生在这个世界上了" << endl;
    };
};

//------------------------------------------------------------------------------
//山脉类类怪物
class M_Undead_Mountain : public Monster
{
public:
    M_Undead_Mountain(int life, int magic, int attack):Monster(life, magic, attack)
    {
        cout << "一只山脉的亡灵类怪物诞生在这个世界上了" << endl;
    };
};

class M_Element_Mountain : public Monster
{
public:
    M_Element_Mountain(int life, int magic, int attack):Monster(life, magic, attack)
    {
        cout << "一只山脉的元素类怪物诞生在这个世界上了" << endl;
    };
};

class M_Mechanic_Mountain : public Monster
{
public:
    M_Mechanic_Mountain(int life, int magic, int attack):Monster(life, magic, attack)
    {
        cout << "一只山脉的机械类怪物诞生在这个世界上了" << endl;
    };
};

//------------------------------------------------------------------------------
//城镇类怪物
class M_Undead_Town : public Monster
{
public:
    M_Undead_Town(int life, int magic, int attack):Monster(life, magic, attack)
    {
        cout << "一只城镇的亡灵类怪物诞生在这个世界上了" << endl;
    };
};

class M_Element_Town : public Monster
{
public:
    M_Element_Town(int life, int magic, int attack):Monster(life, magic, attack)
    {
        cout << "一只城镇的元素类怪物诞生在这个世界上了" << endl;
    };
};

class M_Mechanic_Town : public Monster
{
public:
    M_Mechanic_Town(int life, int magic, int attack):Monster(life, magic, attack)
    {
        cout << "一只城镇的机械类怪物诞生在这个世界上了" << endl;
    };
};

class M_ParFactory
{
public:
    virtual Monster* createMonster_Undead() = 0;
    virtual Monster* createMonster_Element() = 0;
    virtual Monster* createMonster_Mechanic() = 0;
    virtual ~M_ParFactory(){}
};

//工厂子类:
//-------------------------------------------------------------------------------------
//沼泽地区工厂
class M_Factory_Swamp : public M_ParFactory
{
public:
    virtual Monster* createMonster_Undead()
    {
        return new M_Undead_Swamp(300, 50, 120);
    }

    virtual Monster* createMonster_Element()
    {
        return new M_Element_Swamp(200, 80, 110);
    }

    virtual Monster* createMonster_Mechanic()
    {
        return new M_Mechanic_Swamp(400, 0, 90);
    }
};

//-------------------------------------------------------------------------------------
//山脉地区工厂
class M_Factory_Mountain : public M_ParFactory
{
public:
    virtual Monster* createMonster_Undead()
    {
        return new M_Undead_Mountain(300, 50, 80);
    }

    virtual Monster* createMonster_Element()
    {
        return new M_Element_Mountain(200, 80, 100);
    }

    virtual Monster* createMonster_Mechanic()
    {
        return new M_Mechanic_Mountain(600, 0, 110);
    }
};

//-------------------------------------------------------------------------------------
//城镇地区工厂
class M_Factory_Town : public M_ParFactory
{
public:
    virtual Monster* createMonster_Undead()
    {
        return new M_Undead_Town(300, 50, 80);
    }

    virtual Monster* createMonster_Element()
    {
        return new M_Element_Town(200, 80, 100);
    }

    virtual Monster* createMonster_Mechanic()
    {
        return new M_Mechanic_Town(400, 0, 110);
    }
};

总结:抽象工厂模式通过增加新代码不是修改原有代码来为游戏增加新功能。如果需要需要产品族,还需要修改工厂父类来增加新的虚函数以支持新类型,各个工厂有需要增加对新类型的支持,那么这种情况下破坏了开闭原则,同时也不适用抽象工厂模式。抽象工厂模式具备工厂模式的优点,如果只是增加新的产品族,则只需要增加新的子工厂类,符合开闭原则,这是抽象工厂模式优点,但是如果增加新的产品等级结构,那么就需要修改抽象层的代码,这是抽象工厂模式的缺点,因此应该避免在产品等级结构不稳定的情况下使用该模式。引入抽象工厂模式实现意图是:提供一个接口让该接口负责创建一系列相关或者相互依赖的对象,而无需制定它们的具体类。

4、三个模式间对比

1)从代码实现复杂度上,简单工厂模式最简单,工厂方法模式次之,抽象工厂模式最复杂。把简单工厂模式中的代码修改得符合开闭原则,就变成了工厂方法模式,修改工厂方法模式的代码是一个工厂支持对多个具体产品的生产,就变成了抽象工厂模式。

2)从需要的工厂数量上,简单工厂模式需要的工厂数量最少,工厂方法模式需要的工厂数量最多,抽象工厂模式能够有效地减少工厂方法模式所需要的工厂数量。

3)从实际应用上,当项目中的产品数量较少时考虑使用简单工厂模式,如果项目稍大一点或者为了满足开闭原则,则可以使用工厂方法模式,而对于大型项目中有众多厂商并且每个厂商都生产一系列产品时应考虑使用抽象工厂模式。

相关文章:

C++设计模式创建型之工厂模式整理

一、工厂模式分类 工厂模式属于创建型模式&#xff0c;一般可以细分为简单工厂模式、工厂模式和抽象工厂模式。每种都有不同的特色和应用场景。 二、工厂模式详情 1、简单工厂模式 1&#xff09;概述 简单工厂模式相对来说&#xff0c;在四人组写的《设计模式------可复用面…...

前端安全XSS和CSRF讲解

文章目录 XSSXSS攻击原理常见的攻击方式预防措施 CSRFCSRF攻击原理常见攻击情景预防措施&#xff1a; CSRF和XSS的区别 XSS 全称Cross Site Scripting&#xff0c;名为跨站脚本攻击。为啥不是单词第一个字母组合CSS&#xff0c;大概率与样式名称css进行区分。 XSS攻击原理 不…...

本地化部署自建类ChatGPT服务远程访问

本地化部署自建类ChatGPT服务远程访问 文章目录 本地化部署自建类ChatGPT服务远程访问前言系统环境1. 安装Text generation web UI2.安装依赖3. 安装语言模型4. 启动5. 安装cpolar 内网穿透6. 创建公网地址7. 公网访问8. 固定公网地址 &#x1f340;小结&#x1f340; 前言 Te…...

一、Webpack相关(包括webpack-dev-server用以热更新和html-webpack-plugin)

概念与功能&#xff1a; webpack是前端项目工程化的具体解决方案。它提供了友好的前端模块化开发支持&#xff0c;以及代码压缩混淆、处理浏览器端JavaScript的兼容性、性能优化等强大的功能。 快速上手&#xff1a;隔行变色 -S实际是--save的简写&#xff0c;表示安装的第三方…...

安全防御(3)

1.总结当堂NAT与双机热备原理&#xff0c;形成思维导图 2.完成课堂nat与双机热备试验 引用IDS是指入侵检测系统&#xff0c;它可以在网络中检测和防御入侵行为。IDS的签名是指根据已知入侵行为的特征制定的规则&#xff0c;用于检测和警告可能存在的入侵行为。签名过滤器可以根…...

AR远程专家指导在汽车改装上的应用有哪些?

随着科技的不断发展&#xff0c;AR增强现实技术逐渐走进了我们的生活。加上商贸国际化&#xff0c;远程协同纵深到制造生产的更多环节&#xff0c;研发协同、工艺优化等场景复杂、跨层级、需要频繁沟通确认的流程正通过AR应用实现全面远程化的过渡&#xff0c;在汽车行业&#…...

css-3:什么是响应式设计?响应式的原理是什么?如何做?

1、响应式设计是什么&#xff1f; 响应式网站设计&#xff08;Responsive WEB desgin&#xff09;是一个网络页面设计布局&#xff0c;页面的设计与开发应当根据用户行为以及设备环境&#xff08;系统平台、屏幕尺寸、屏幕定向等&#xff09;进行相应的相应和调整。 描述响应式…...

Armstrong数,n位数等于其各位数的n次方之和。

//Armstrong数具有以下特征&#xff1a;一个n位数等于其各位数的n次方之和。 //例如&#xff1a;1531^35^33^3 16341^46^43^44^4 #include<stdio.h> #include<math.h> //实在不知道的暴力求解方法 int main() {//Armstrong数具有以下特征&#xff1a;一个…...

blender的下载安装和配置中文环境

引言 在3D建模和动画设计领域&#xff0c;Blender 作为一款强大且免费的开源软件&#xff0c;一直以优秀的性能和对众多技术的支持赢得了大批用户的喜爱。然而&#xff0c;对于刚接触这款软件的用户而言&#xff0c;其安装和配置过程可能会带来一定困扰&#xff0c;尤其是在设…...

MyCat配置rule.xml、server.xml讲解

1. rule.xml分片规则配置文件 rule.xml中配置的主要就是拆分表的规则&#xff0c;rule.xml中主要包含两类标签 tableRule 和Function。 tableRule标签里面主要配置我们的分片规则&#xff0c;Function里面涉及的是分片规则里面所涉及的java类&#xff0c;都是在function中配置…...

Linux项目部署

目录 一JAVAWeb环境的部署【安装JDK&#xff0c;MySQL数据库&#xff0c;Tomcat】 二.手工部署SpringBoot项目&#xff08;写的最好的&#xff09; 1.在IDEA中开发SpringBoot项目并打成jar包--点击右侧的Maven执行package命令 2.将jar包上传到Linux服务器 3.执行以下命令&a…...

案例:Docker 镜像的创建及使用(commit与dockerfile方式)

文章目录 1、commit方式创建镜像1.1、前期准备1.2、制成镜像1.3、启动镜像1.3.1、启动镜像启动nginx1.3.2、一个命令直接全部启动1.3.3、两种方式区别 1.4、commit创建镜像方式的本质 2、Dockerfile的使用2.1、Dockerfile指令2.2、nginx镜像制作案例2.3、查看构建历史&#xff…...

QGIS二次开发三:显示Shapefile

Shapefile 为 OGR 所支持的最重要的数据格式之一&#xff0c;自然可以被 QGIS 加载。那么该如何显示Shapefile呢&#xff1f; 一、先上代码 #include <qgsapplication.h> #include <qgsproviderregistry.h> #include <qgsmapcanvas.h> #include <qgsvec…...

FFmpeg中相关结构体介绍

AVFormatContext&#xff1a;此结构体存储音视频封装格式中包含的信息&#xff0c;并且这个结构体是贯穿整个播放流程的。在这个结构体中主要包含AVInputFormat&#xff0c;AVOutputFormat、AVStream等。 struct AVInputFormat *iformat; // 输入数据的封装格式 AVIOContext *…...

Llama 2 云端部署与API调用【AWS SageMaker】

Meta 刚刚发布了 Llama 2 大模型。如果你和我们一样&#xff0c;你一定会迫不及待地想要亲自动手并用它来构建。 推荐&#xff1a;用 NSDT设计器 快速搭建可编程3D场景。 使用任何类型的 LLM 进行构建的第一步是将其托管在某处并通过 API 使用它。 然后你的开发人员可以轻松地将…...

根文件系统制作

1.官网下载工具 制作工具&#xff1a;busybox https://busybox.net/downloads/ 2.制作根文件系统 2.1准备工作 a.把压缩包放在FSP1M目录下&#xff0c;并解压 2.2正式开始 2.2.1配置交叉编译工具链 1. 打开Makefile文件 2. 修改ARCH &#xff1f;$(SUBARCH) &#xf…...

Linux ARM64架构 动态替换 altinstructions

文章目录 简介一、altinstructions节1.1 .altinstructions1.2 .rela.altinstructions 二、内核模块重定位源码分析参考资料 简介 在内核开发中&#xff0c;有时需要对内核代码进行修补&#xff0c;以解决bug、优化性能或引入新功能。替代指令&#xff08;altinstructions&…...

Mac显示隐藏文件夹

1、设置隐藏文件可见 defaults write com.apple.finder AppleShowAllFiles TRUE 2、killall Finder killall Finder...

使用 Habana Gaudi2 加速视觉语言模型 BridgeTower

&#x1f917; 宝子们可以戳 阅读原文 查看文中所有的外部链接哟&#xff01; 在对最先进的视觉语言模型 BridgeTower 进行微调时&#xff0c;使用 Optimum Habana v1.6&#xff0c; Habana Gaudi2 可以达到 近 3 倍于 A100 的速度。硬件加速的数据加载以及 fast DDP 这两个新特…...

mysql查询语句之实践篇

基础查询语句 完整语法格式如下&#xff1a; select 字段列表 from 表名列表 where 条件列表 group by 分组字段 having 分组之后的条件 order by 排序 limit 分页限定 -- 创建表 create table stu(id int,name varchar(20),chinese double,english double,math double ); --…...

OpenClaw 的模型架构中,是否使用了混合专家(MoE)的负载均衡策略?

关于OpenClaw模型架构中是否采用了混合专家&#xff08;MoE&#xff09;的负载均衡策略&#xff0c;这个问题其实触及了当前大模型设计里一个相当有意思的细节。直接说结论的话&#xff0c;从目前公开的论文和技术报告来看&#xff0c;OpenClaw并没有明确声明在其MoE层中使用了…...

机器人避障轨迹优化实战:用Python+Scipy从数学推导到完整代码实现

机器人避障轨迹优化实战&#xff1a;PythonScipy从数学建模到工程实现 当你在机器人实验室里第一次看到机械臂撞翻咖啡杯&#xff0c;或是无人机在演示中撞上窗帘时&#xff0c;就会明白轨迹优化不仅仅是数学公式——它是让机器人安全高效工作的核心技术。本文将带你从零开始&a…...

LumiPixel Canvas Quest超现实主义创作:生成融合自然与机械的赛博格人像

LumiPixel Canvas Quest超现实主义创作&#xff1a;生成融合自然与机械的赛博格人像 1. 当AI画笔遇见赛博格幻想 打开LumiPixel Canvas Quest的第一感觉&#xff0c;就像拿到了通往异世界的钥匙。这个擅长超现实题材的AI艺术工具&#xff0c;最近在我们团队内部掀起了一阵&qu…...

探索CELLxGENE:突破单细胞数据分析壁垒的交互可视化指南

探索CELLxGENE&#xff1a;突破单细胞数据分析壁垒的交互可视化指南 【免费下载链接】cellxgene An interactive explorer for single-cell transcriptomics data 项目地址: https://gitcode.com/gh_mirrors/ce/cellxgene 单细胞转录组学研究正以前所未有的分辨率揭示细…...

CPUDoc:解锁CPU隐藏性能的智能优化工具

CPUDoc&#xff1a;解锁CPU隐藏性能的智能优化工具 【免费下载链接】CPUDoc 项目地址: https://gitcode.com/gh_mirrors/cp/CPUDoc 在当今计算环境中&#xff0c;CPU性能优化已成为提升整体系统体验的关键因素。CPUDoc作为一款免费开源的CPU辅助工具&#xff0c;通过创…...

自动送料装车系统PLC控制的设计——24页

自动送料装车系统作为工业自动化领域的关键环节&#xff0c;其核心作用在于通过PLC&#xff08;可编程逻辑控制器&#xff09;实现物料输送、定位、装载等流程的精准控制。传统人工操作易受疲劳、环境等因素影响&#xff0c;导致效率波动与安全隐患。而PLC控制通过预设逻辑程序…...

【开题答辩全过程】以 基于Android的收支记账管理系统为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…...

Fish-Speech 1.5应用案例:从播客配音到语音提醒,实战分享

Fish-Speech 1.5应用案例&#xff1a;从播客配音到语音提醒&#xff0c;实战分享 1. 项目概述与核心优势 Fish-Speech 1.5作为新一代文本转语音(TTS)系统&#xff0c;凭借其创新的DualAR架构在语音合成领域脱颖而出。这个开源项目通过双自回归Transformer设计&#xff0c;主T…...

Java 使用国密算法实现数据加密传输

本文是混合加密&#xff1a;前端 SM2 SM4&#xff0c;后端 Spring Boot Hutool 解密的完整示例。 方案的逻辑是&#xff1a; 前端随机生成一个 SM4 key 用 SM4 加密整个业务 JSON 用后端提供的 SM2 公钥 加密这个 SM4 key 后端先用 SM2 私钥 解出 SM4 key 再用 SM4 解出…...

告别临时表!MySQL8窗口函数优化复杂统计查询的3种典型方案

MySQL8窗口函数实战&#xff1a;3种替代临时表的高效统计方案 在数据分析与报表生成场景中&#xff0c;开发人员经常需要处理复杂的多维度统计需求。传统解决方案往往依赖临时表和多次查询拼接&#xff0c;不仅代码冗长&#xff0c;还存在显著的性能瓶颈。MySQL8引入的窗口函数…...