C++ 设计模式——抽象工厂模式
抽象工厂模式
抽象工厂模式
- 抽象工厂模式
- 主要组成部分
- 代码实现
- 抽象工厂模式模式的 UML 图
- 抽象工厂模式 UML 图解析
- 优点和缺点
- 适用场景
抽象工厂模式提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们的具体类。它通常用于需要创建多个产品族的场景。
引入“抽象工厂模式”设计模式的定义(实现意图):提供一个接口,让该接口负责创建一系列相关或者相互依赖的对象,而无须指定它们具体的类。
主要组成部分
- 抽象工厂(AbstractFactory):定义创建抽象产品的接口。它声明了用于创建不同类型产品的方法。
- 具体工厂(ConcreteFactory):实现抽象工厂接口,创建具体产品。每个具体工厂负责生成一组相关的具体产品。
- 抽象产品(AbstractProduct):定义产品的接口。它为具体产品提供了一个公共的接口。
- 具体产品(ConcreteProduct):实现抽象产品接口的具体类。每个具体产品对应于一个具体工厂。
代码实现
以下是使用抽象工厂模式创建不同类型的怪物对象的代码示例:
#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_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() override {return new M_Undead_Swamp(300, 50, 120); // 创建沼泽亡灵类怪物}virtual Monster* createMonster_Element() override {return new M_Element_Swamp(200, 80, 110); // 创建沼泽元素类怪物}virtual Monster* createMonster_Mechanic() override {return new M_Mechanic_Swamp(400, 0, 90); // 创建沼泽机械类怪物}
};// 山脉地区的工厂
class M_Factory_Mountain : public M_ParFactory {
public:virtual Monster* createMonster_Undead() override {return new M_Undead_Mountain(300, 50, 80); // 创建山脉亡灵类怪物}virtual Monster* createMonster_Element() override {return new M_Element_Mountain(200, 80, 100); // 创建山脉元素类怪物}virtual Monster* createMonster_Mechanic() override {return new M_Mechanic_Mountain(600, 0, 110); // 创建山脉机械类怪物}
};// 城镇的工厂
class M_Factory_Town : public M_ParFactory {
public:virtual Monster* createMonster_Undead() override {return new M_Undead_Town(300, 50, 80); // 创建城镇亡灵类怪物}virtual Monster* createMonster_Element() override {return new M_Element_Town(200, 80, 100); // 创建城镇元素类怪物}virtual Monster* createMonster_Mechanic() override {return new M_Mechanic_Town(400, 0, 110); // 创建城镇机械类怪物}
};// 使用示例
int main() {M_ParFactory* factory = new M_Factory_Swamp();Monster* undead = factory->createMonster_Undead();Monster* element = factory->createMonster_Element();Monster* mechanic = factory->createMonster_Mechanic();// 释放内存delete undead;delete element;delete mechanic;delete factory;return 0;
}
抽象工厂模式模式的 UML 图

抽象工厂模式 UML 图解析
- 类与类之间的关系:
Monster类是所有具体怪物类的父类,子类(如M_Undead_Swamp、M_Element_Swamp、M_Mechanic_Swamp等)通过实线箭头与父类连接,箭头指向Monster类,表示继承关系。M_ParFactory是抽象工厂类,定义了创建不同类型怪物的接口。具体工厂类(如M_Factory_Swamp、M_Factory_Mountain、M_Factory_Town)通过实线箭头与M_ParFactory类连接,表示继承关系。
- 依赖关系:
- 具体工厂类(如
M_Factory_Swamp等)与具体怪物类(如M_Undead_Swamp等)之间存在虚线箭头,表示依赖关系。具体工厂类负责实例化具体怪物类的对象,箭头指向被实例化的类。
- 具体工厂类(如
- 稳定与变化部分:
- 稳定部分:
Monster类和M_ParFactory类是稳定部分,不需要频繁修改。 - 变化部分:具体怪物类(如
M_Undead_Swamp、M_Element_Swamp等)和具体工厂类(如M_Factory_Swamp等)属于变化部分。当需要添加新类型的怪物时,只需增加新的具体工厂类和具体怪物类,而不需要修改稳定部分。
- 稳定部分:
- 扩展性:
- 当需要引入新类型的怪物(如
M_Beast),只需创建一个新的具体工厂类(如M_Factory_Beast)和对应的怪物类(如M_Beast),而不需要更改现有的工厂接口。这符合开闭原则:对扩展开放,对修改关闭。
- 当需要引入新类型的怪物(如
- 隐藏实现细节:
- 如果
M_ParFactory类及其具体实现由第三方开发,开发者只需通过抽象工厂接口与工厂交互,而无需了解具体的怪物类(如M_Undead_Swamp等),实现了对具体实现的隐藏。
- 如果
- 接口扩展:
M_ParFactory中的接口可以根据需要进行扩展,例如新增创建其他类型对象的方法(如 NPC),使得工厂能够支持更丰富的对象创建。
优点和缺点
优点:
- 解耦合:客户端代码与具体产品的实现解耦,便于维护和扩展。修改产品的实现不会影响到客户端。
- 一致性:可以确保一组产品的一致性,避免在创建产品时出现不匹配的情况。例如,创建一个特定类型的怪物时,工厂会确保所有相关的属性和行为都符合预期。
- 易于扩展:新增产品类型时,只需扩展工厂类和相应的产品类,而无需修改现有代码,符合开闭原则。
- 隔离变化:将产品的创建逻辑集中在工厂中,减少了产品类之间的依赖,便于管理和控制变化。
缺点:
- 系统复杂性增加:引入抽象工厂模式会增加系统的复杂性,特别是在产品种类较多时,工厂类和产品类的数量也会增加。
- 维护成本:随着产品族的增加,维护抽象工厂及其子类的成本可能会提升,特别是当需要对多个工厂进行修改时。
- 难以支持新产品:如果需要支持新类型的产品,可能需要修改现有的工厂接口和实现,这可能导致较大的代码变动。
- 运行时开销:由于使用了多层抽象,可能会引入一定的运行时开销,尤其是在频繁创建对象的场景中。
适用场景
- 产品族的创建:当系统需要创建一组相关或相互依赖的产品时,使用抽象工厂模式可以确保产品的一致性和完整性。
- 需要解耦的系统:当需要将产品的创建与使用分离,减少系统之间的耦合度时,抽象工厂模式是一个理想的选择。
- 需要支持多个产品变体:在需要支持不同变体的情况下,例如不同地区的怪物、不同类型的用户界面组件等,抽象工厂模式可以有效管理这些变体。
- 需要扩展产品类型:当系统需要频繁扩展新产品类型时,抽象工厂模式提供了良好的扩展机制,符合开闭原则。
- 框架设计:在设计框架或库时,抽象工厂模式可以为用户提供灵活的产品创建接口,用户可以根据需要实现具体的工厂类。
相关文章:
C++ 设计模式——抽象工厂模式
抽象工厂模式 抽象工厂模式 抽象工厂模式主要组成部分代码实现抽象工厂模式模式的 UML 图抽象工厂模式 UML 图解析优点和缺点适用场景 抽象工厂模式提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们的具体类。它通常用于需要创建多个产品…...
《亿级流量系统架构设计与实战》第十一章 Timeline Feed服务
Timeline Feed服务 一、概述1、分类2、功能 二、设计原理1、拉模式与用户发件箱2、推模式与用户收件箱3、推拉模式结合 三、关键技术1、内容与用户收件箱的交互(推模式)2、推送拆分子任务3、收件箱模型设计 内容总结自《亿级流量系统架构设计与实战》 一…...
氙灯老化试验箱试验机
氙灯老化试验箱,采用6.5KW大功率的精密水冷式氙灯,曝晒面积达到了6500cm2 功能强大,测试结果可靠 ◆ 满足国内外所有氙灯测试标准要求。 ◆ 采用氙灯灯管及滤光器组件,保证试验数据的可比性和重现性。 ◆ 自动旋转式三层鼓型样板架…...
【Qt】常用控件QRadioButton
常用控件QRadioButton QRadioButton是单选按钮,可以在多个选项中选择一个。 作为QAbstractButton和QWidget的子类,其属性和用法,对于QRadioButton同样适用。 属性说明 checkable 是否能选中 checked 是否已经被选中. checkable 是 checked…...
Mysql 离线版下载安装-(详细版)
Mysql 离线版下载安装-(详细版) 文章目录 Mysql 离线版下载安装-(详细版)1.0 下载地址2.0 解压到本地2.0.1 配置环境变量2.0.2 新建mysql配置文件ini2.0.3使用管理员启动 cmd 3.0 初始化密码忘记了4.0 修改初始化密码5.0 使用可视化工具登录Mysql 1.0 下载地址 地址࿱…...
Spring Boot和OCR构建车牌识别系统
博客主页: 南来_北往 系列专栏:Spring Boot实战 OCR介绍 OCR(Optical Character Recognition)是光学字符识别技术的缩写,它能够将图像中的文本转换为机器可读和编辑的数字文本格式。这种技术广泛应用于数据输入、文档管理…...
Java-自定义注解中成员变量是Class<?>
在Java中,自定义注解可以包含各种类型的成员变量,包括 Class<?> 类型。这种类型的成员变量 通常用于表示某个类的类型信息。下面我将详细介绍如何定义一个包含 Class<?> 类型成员变量的 自定义注解,并给出一些示例代码。 1. 定义自定义注解 定义一个自定义…...
SX_UNIX套接字通信_15
UNIX套接字通信的优势: UNIX套接字通信常用于一个项目中的进程之间通信,UNIX提供了与网络套接字相似的特性,但是避免了网络延迟,提高了性能,但是它只能在同一台机器上使用,无法跨越网络的进程间通信 实例&…...
JS模块化总结 | CommonJS、ES6
BV13W42197jR 个人笔记 目录 JS模块化基础知识1. 概述1.1 什么是模块化1.2 为什么需要模块化? 2 模块化规范3 导入&导出4 CommonJS规范4.1 初步体验4.2 导出数据4.3 导入数据4.4 扩展理解4.5 浏览器端运行 5 ES6模块化规范5.1 初步体验5.2 Node中运行ES65.3 导出数据①分别…...
25考研计算机组成原理复习·3.5高速缓冲存储器
高速缓冲存储器Cache 工作原理:将某些主存块复制到Cache中,缓和CPU与主存之间的速度矛盾局部性原理 时间局部性:现在访问的地址,不久之后也很可能被再次访问空间局部性:现在访问的地址,其附近的地址也很可…...
餐厅管理系统
目录 一、 系统简介 1.1需求分析 1.2 编程环境与工具 二、 系统总体设计 2.1 系统的功能模块图。 2.2 各功能模块简介。 三、 主要业务流程 (1)用户及管理员登录流程图 (2)信息添加流程 (3…...
杭州百腾教育科技 TiDB 6.5 to 7.5 升级记录
作者: reAsOn2010 原文来源: https://tidb.net/blog/612103f3 背景 使用 TiDB 作为我们的全量数据库已经有六七年了,当时还是 2.0 版本。早期TiDB的迭代和新特性的发布对于实际使用的影响还是很大的,所以从那个时候开始就有每…...
Redis的缓存穿透、击穿、雪崩
目录 缓存穿透 定义: 解决方法: 缓存击穿 定义: 解决方案: 缓存雪崩 定义: 解决方案: 缓存穿透、缓存击穿和缓存雪崩的区别 缓存穿透 定义: 查询一个不存在的数据,数据库未…...
【Django开发】前后端分离django美多商城项目第1篇:欢迎来到美多 项目主要页面介绍【附代码文档】
本教程的知识点为: 项目准备 项目准备 配置 1. 修改settings/dev.py 文件中的路径信息 2. INSTALLED_APPS 3. 数据库 用户部分 图片 1. 后端接口设计: 视图原型 2. 具体视图实现 用户部分 使用Celery完成发送 判断帐号是否存在 1. 判断用户名是否存在 后…...
【软件造价咨询】信息化项目预算评审看什么?
在信息化项目预算评审中,各方往往只重视预算金额部分,而忽视了项目建设的全局性和整体性把关,导致信息系统的重复建设、分散建设、业务和系统两张皮、重功能轻数据、重投资轻方案等问题频出,从而大幅降低财政投资效益。 例如&…...
第37讲:Cephfs文件系统的正确使用姿势
文章目录 1.Cephfs文件系统简介2.Cephfs文件系统细节介绍2.1.Cephfs文件系统多客户端隔离挂载2.2.Ceph集群中多个Cephfs如何单独使用 3.挂载多个Cephfs文件系统4.Cephfs文件系统多客户端隔离挂载实战4.1.创建一个Cephfs文件系统4.2.将Cephfs文件系统挂载到本地路径4.3.在Cephfs…...
单片机烧录
在设计芯片的时候,关于烧录的环节是一个不得不考虑的问题。 我们首先排除掉,由外部直接硬件操控FLASH 的方案,这个方案有很多缺点。 1、每个IC使用的FLASH型号是各不相同的,每种型号的FLASH的烧录命令和流程都有差别,这…...
mysql实现分布式锁
利用数据库的悲观锁实现分布式锁,实际应用中要考虑mysql的高可用。 DistributedLock.h #ifndef DistributedLock_H_ #define DistributedLock_H_// // DistributedLock.h: // #include "base/MySQLDriver.h" class CDistributedLock { public://// Construction/D…...
MySQL快速使用
关系型数据库(RDBMS):建立在关系模型基础上,由多张相互连接的二维表组成的数据库 特点:使用表存储数据,格式统一方便维护;使用SQL语言操作,标准统一使用方便 通用语法: …...
LeetCode41.缺失的第一个正数
1. 题目大意 给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。 请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。 2. 思路分析 示例 1: 输入:nums [3,4,-1,1] 输出:2 解释࿱…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
基于Springboot+Vue的办公管理系统
角色: 管理员、员工 技术: 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能: 该办公管理系统是一个综合性的企业内部管理平台,旨在提升企业运营效率和员工管理水…...
【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...
ubuntu22.04 安装docker 和docker-compose
首先你要确保没有docker环境或者使用命令删掉docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker 更新软件环境 sudo apt update sudo apt upgrade下载docker依赖和GPG 密钥 # 依赖 apt-get install ca-certificates curl gnupg lsb-rel…...
