C++ 设计模式——工厂方法模式

工厂方法模式

      • 工厂方法模式
        • 主要组成部分
        • 代码实现
        • 工厂方法模式模式的 UML 图
        • 工厂方法模式 UML 图解析
        • 优点和缺点
        • 适用场景

工厂方法模式

工厂方法模式是一种创建型设计模式,它通过定义一个接口用于创建对象,但由子类决定实例化哪个类。与简单工厂模式不同,工厂方法模式将对象的创建委托给子类,从而实现更好的扩展性和灵活性。

引入“工厂方法模式(实现意图):定义一个用于创建对象的接口,但由子类决定要实例化的类是哪一个。该模式使得某个类的实例化延迟到子类。

主要组成部分
  • 产品接口(Product):定义了工厂方法所创建的对象的接口。
  • 具体产品(ConcreteProduct):实现了产品接口的具体类。
  • 工厂接口(Creator):声明了工厂方法,返回一个产品对象。
  • 具体工厂(ConcreteCreator):实现了工厂接口,返回具体产品的实例。
代码实现

以下代码,主要用工厂方法模式创建不同类型的怪物对象:

#include <iostream>
#include <string>using namespace std;// 怪物父类
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 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* factory)
{return factory->createMonster(); // 根据工厂创建怪物
}// 创建怪物工厂子类模板
template <typename T>
class M_ChildFactory : public M_ParFactory
{
public:virtual Monster* createMonster() {return new T(300, 50, 80); // 创建具体类型的怪物}
};// 使用示例
int main()
{// 使用具体工厂创建怪物M_ParFactory* undeadFactory = new M_UndeadFactory();Monster* undead = Gbl_CreateMonster(undeadFactory);delete undead; // 释放内存delete undeadFactory;M_ParFactory* elementFactory = new M_ElementFactory();Monster* element = Gbl_CreateMonster(elementFactory);delete element; // 释放内存delete elementFactory;M_ParFactory* mechanicFactory = new M_MechanicFactory();Monster* mechanic = Gbl_CreateMonster(mechanicFactory);delete mechanic; // 释放内存delete mechanicFactory;// 使用模板工厂创建怪物M_ChildFactory<M_Undead> undeadChildFactory;Monster* undeadChild = Gbl_CreateMonster(&undeadChildFactory);delete undeadChild; // 释放内存return 0;
}
工厂方法模式模式的 UML 图

工厂方法模式模式的 UML 图

工厂方法模式 UML 图解析
  • 类关系
    • Monster:抽象基类,定义了怪物的基本属性(如 m_lifem_magicm_attack)。
    • M_UndeadM_ElementM_Mechanic:具体类,继承自 Monster,实现不同类型的怪物。
  • 工厂类
    • M_ParFactory:抽象工厂类,定义了创建怪物的接口 createMonster
    • M_UndeadFactoryM_ElementFactoryM_MechanicFactory:具体工厂类,继承自 M_ParFactory,分别负责创建不同类型的怪物。
    • M_ChildFactory:模板工厂类,能够创建任意类型的怪物,提供更灵活的创建方式。
  • 稳定部分
    • Gbl_CreateMonster 函数依赖的 Monster 类和 M_ParFactory 类属于稳定部分,不需要更改。
  • 变化部分
    • M_UndeadFactoryM_ElementFactoryM_MechanicFactory 类以及具体怪物类(如 M_UndeadM_Mechanic)属于变化部分。Gbl_CreateMonster 函数不依赖于这些变化部分。
  • 扩展新类型
    • 当需要引入新怪物类型(例如 M_Beast)时,无需更改 Gbl_CreateMonster 函数或修改 MonsterFactorycreateMonster 方法。只需创建一个继承自 Monster 的新类 M_Beast 和一个继承自 M_ParFactory 的新工厂类 M_BeastFactory,这符合开闭原则:对扩展开放,对修改关闭。
  • 隐藏实现细节
    • 如果 M_ParFactory 及其子类由第三方开发,工厂方法模式可以有效隐藏具体怪物类(如 M_UndeadM_ElementM_Mechanic),避免暴露给开发者。
  • 接口扩展
    • M_ParFactory 的接口可以根据需要扩展,例如增加对 NPC(非玩家角色,如商人、路人等)的创建支持,或为 createMonster 提供默认实现。
  • 增加工厂类的代价
    • 增加新的工厂类是工厂方法模式的必然代价,但这为系统的灵活性和可扩展性提供了保障。
优点和缺点
  • 优点
    • 符合开闭原则:新增产品时,只需创建新的产品类和相应的工厂类,无需修改现有代码。
    • 减少耦合:客户端代码与具体产品类解耦,依赖于抽象工厂接口,增强了系统的灵活性。
    • 扩展性强:可以方便地扩展新的产品类型,适合复杂系统的需求变化。
    • 提高代码可读性:通过明确的工厂类和产品类的分离,代码结构更加清晰。
  • 缺点
    • 类的数量增加:每新增一种产品都需要创建相应的工厂类,可能导致类的数量剧增,增加系统复杂性。
    • 实现复杂性:对于简单产品的创建,工厂方法模式可能显得过于复杂,增加不必要的开销。
    • 难以管理:如果产品种类过多,可能导致工厂类的管理变得困难。
适用场景
  • 产品族:需要创建一系列相关或相互依赖的对象时,工厂方法模式非常适合。
  • 产品类型变化频繁:当产品类型经常变化,且需要动态地扩展新产品时,工厂方法模式提供了良好的灵活性。
  • 需要解耦的系统:当系统需要将对象创建与使用分离时,工厂方法模式可以有效降低耦合度。
  • 复杂对象的创建:当对象的创建过程复杂,且可能涉及多个步骤时,工厂方法模式可以封装这些复杂性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/404126.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring项目:文字花园(三)

一.实现博客详情 1.后端逻辑代码 controller层添加方法&#xff08;根据博客id查看博客详情&#xff09; RequestMapping("/getBlogDetail")public Result<BlogInfo> getBlogDetail(Integer blogId){log.info("getBlogDetail, blogId: {}", blogId…

vue 后台管理 之 状态管理 vuex 的使用

幸福是一种能力 文章目录 一、数据驱动视图二、VueX 数据公共池 一、数据驱动视图 我们都知道 vue 之所以好用&#xff0c;是因为官方帮我们做了数据驱动视图初始化时将数据和视图进行绑定&#xff0c;通过 watcher 来监听数据的变化&#xff0c;当数据变化时&#xff0c;会触…

这三大创意神器,一个不用就是错过了一个小目标!

【导语】在这个充满无限可能的数字时代&#xff0c;创意成为了推动我们前行的强大动力。但你是否曾因视频背景杂乱无章而苦恼&#xff1f;是否渴望将静态图片瞬间赋予生命&#xff1f;又或是对模糊照片中的珍贵瞬间束手无策&#xff1f;今天&#xff0c;就让我们揭秘三大变态且…

Linux搭建环境:从零开始掌握基础操作(二)

​ ​ 您好&#xff0c;我是程序员小羊&#xff01; 前言 软件测试第一步就是搭建测试环境&#xff0c;如何搭建好测试环境&#xff0c;需要具备两项的基础知识&#xff1a; 1、Linux 命令: 软件测试第一个任务, 一般都需要进行环境搭建, 一部分&#xff0c;环境搭建内容是在服…

Your local changes would be overwritten by merge git

方法二 直接覆盖本地的代码&#xff0c;放弃自己本地的改动&#xff0c;只保留服务器端代码 直接回退到上一个版本&#xff0c;再进行pull。 【步骤】 直接 VCS -> Git -> Reset HEAD… 选择需要的reset模式&#xff1a;hard&#xff08;即放弃本地代码&#xff0c;新修…

JavaScript基础——闭包

闭包简介 闭包的作用 闭包可以保留变量的状态 闭包可以让变量私有化 闭包的缺点 闭包简介 在JavaScript中&#xff0c;重复声明同一个变量会导致变量冲突&#xff0c;在这个时候可以使用闭包创建独立的执行环境。 在JavaScript中&#xff0c;闭包是指封闭的执行环境&#xff…

【图像去噪】论文精读:Toward Convolutional Blind Denoising of Real Photographs(CBDNet)

文章目录 前言Abstract1. Introduction2. Related Work2.1. Deep CNN Denoisers2.2. Image Noise Modeling2.3. Blind Denoising of Real Images 3. Proposed Method3.1. Realistic Noise Model3.2. Network Architecture3.3. Asymmetric Loss and Model Objective3.4. Trainin…

Spring IoCDI(下)—DI的尾声

我们之前学习了控制反转IoC&#xff0c;接下来就开始学习依赖注入DI的细节。 依赖注入是一个过程&#xff0c;是指IoC容器在创建Bean时&#xff0c;去提供运行时所依赖的资源&#xff0c;而资源指的就是对象。我们使用 Autowired 注解&#xff0c;完成依赖注入的操作。简单来说…

使用docker compose一键部署redis服务

使用docker compose一键部署redis服务 1、创建安装目录 mkdir /data/redis/ -p && cd /data/redis2、创建docker-compose.yml文件 version: 3 services:redis:image: registry.cn-hangzhou.aliyuncs.com/xiaopangpang/redis:7.0.5container_name: redisrestart: al…

【STM32项目】在FreeRtos背景下的实战项目的实现过程(二)

个人主页~ 实战项目的实现过程&#xff08;一&#xff09;~ 实战项目的实现过程 二、初步了解各个外设硬件1、OLED模块2、GPS模块3、MPU6050模块4、超声测距模块5、温度测控模块6、语音模块7、SIM模块8、按键模块 三、查阅资料1、查看手册2、查找例程 四、研究硬件功能1、OLED…

js使用run编码计算region的交集并集差集

所有shape都转为run编码 转为run编码后再运算可以节约大量内存 subtractIntervals 函数的逻辑:目前的实现假设了所有的 subIntervals 都会与 intervals 完全重叠,这可能导致计算不准确。应该将 subIntervals 从 intervals 中去除时,考虑到可能的部分重叠。 差集计算:sub…

双剑合璧,网络无敌!Windows Server 2012 R2双网卡绑定实战教程

文章目录 双剑合璧&#xff0c;网络无敌&#xff01;Windows Server 2012 R2双网卡绑定实战教程1 背景信息2 配置步骤2.1 登录服务器2.2 分别清除两块网卡的配置2.3 进入“本地服务器”界面2.4 进入“NIC组合”界面2.5 创建网卡绑定组2.6 设置新建组参数2.7 查看已创建的网卡组…

【kubernetes】k8s配置资源管理

一、ConfigMap资源配置 ConfigMap保存的是不需要加密配置的信息 ConfigMap 功能在 Kubernetes1.2 版本中引入&#xff0c;许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。ConfigMap API 给我们提供了向容器中注入配置信息的机制&#xff0c;ConfigMap 可以被…

银河麒麟V10+qt5,12.11编译mysql驱动连接OceanBase数据库

1、下载mysql数据库,解压后里面包含编译所需要的lib和include文件夹,下载地址:https://www.mysql.com/downloads/ 选择适合自己系统的版本: 解压后的文件夹中包含需要的lib和include文件夹: 使用qt打开mysql源码项目: 根据自己qt安装路径,找到项目: 注释掉如图: …

C++STL之string类:相关习题解析

目录 1&#xff0c;字符串转整型数字 2&#xff0c;字符串最后一个单词的长度(getline的使用) 3&#xff0c;仅仅反转字母 4&#xff0c;字符串中的第一个唯一字符(找字符串中第一个只出现一次的字符) 5&#xff0c;验证回文串 6&#xff0c;验证回文串|| 7&#xff0c;…

Vue 3 + 天地图 + D3.js 绘制行政区划

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;组件封装篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来组件封装篇专栏内容:组件封装-天地图 目录 引入天地图 API 初始化地图 引入 D3.js 加载行政区划数据 添…

mysql聚合函数和分组

我最近开了几个专栏&#xff0c;诚信互三&#xff01; > |||《算法专栏》&#xff1a;&#xff1a;刷题教程来自网站《代码随想录》。||| > |||《C专栏》&#xff1a;&#xff1a;记录我学习C的经历&#xff0c;看完你一定会有收获。||| > |||《Linux专栏》&#xff1…

小五金加工:细节决定产品质量与性能

在小五金加工领域&#xff0c;细节往往决定着最终产品的质量、性能以及市场竞争力。看似微不足道的细微之处&#xff0c;实际上蕴含着巨大的影响。时利和将介绍小五金加工中细节的重要性。 首先&#xff0c;细节关乎产品的精度。小五金零件通常尺寸较小&#xff0c;但对精度的要…

TorchChat:Ollama的潜在对手

PyTorch最近发布TorchChat&#xff0c;TorchChat允许在本地台式机、笔记本电脑或移动设备上下载和运行大型语言模型。会不会让你想到什么&#xff0c;没错就是Ollama。TorchChat是一个适应性强的框架&#xff0c;旨在提高各种硬件平台的LLMs效率&#xff0c;有助于在各种设备上…

怎样使用sudo的时候不需要输入密码?

在Ubuntu等Linux系统下&#xff0c;经常要在个人账户使用sudo命令来执行一些需要root权限的命令&#xff0c;但是需要输入该账户的密码&#xff0c;有时候显得很繁琐&#xff0c; 那么怎样使用sudo的时候不需要输入密码呢&#xff1f; 有如下两种方法&#xff1a; 常规方法1…