设计模式之抽象工厂模式(C++)
作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

一、抽象工厂模式是什么?
抽象工厂模式是一种创建型的软件设计模式,该模式相当于升级版的工厂模式。
如果说工厂模式对应一个产品系列,那抽象工厂就对应了多个产品系列。比如工厂模式中有鞋子、衣服和裤子可以生产,那抽象工厂模式就会衍生出耐克工厂和阿迪工厂,这两个工厂分别生产各自品牌的鞋子、衣服和裤子,客户只需要选择具体工厂和想要的产品即可。如果想要替换产品系列,也只需要将具体工厂切换为别的品牌就行了。
抽象工厂模式的优点:
- 具体类分离。具体产品类在具体工厂的实现中进行了分离和归类。
- 易于更换产品族。当客户想要改变整个产品族时,只需要切换具体工厂即可。
- 利于产品一致性。当产品族的各个产品需要在一起执行时,抽象工厂可以确保客户只操作同系列产品,而不会进行跨品牌的组合。
抽象工厂模式的缺点:
- 不利于添加新种类产品。每加一个新的种类,如多一个项链类型的产品,那每一个具体工厂都要进行代码的扩展,且破坏了原先规定的结构,违反了开闭原则。
二、抽象工厂模式
2.1 结构图
客户端即Main主函数,选择具体工厂(族),通过该工厂产生该系列下的具体产品(苹果和香蕉),切换具体工厂,产生新系列的具体产品。

2.2 代码示例
场景描述:我联系了一家中国工厂,品尝该厂的苹果和香蕉,吃完后又找到一家美国工厂,品尝他家的苹果和香蕉,对比下口感。
//Prodect.h
/****************************************************/
#pragma once
#include <iostream>using namespace std;// 抽象产品类
class Prodect
{
public:// 构造函数Prodect(int price) :m_price(price) {};// 析构函数virtual ~Prodect() {};// 获取价格int getPrice() {return m_price;}
protected:// 产品价格int m_price;
};// 抽象产品细分-苹果
class AppleProdect : public Prodect
{
public:// 构造函数AppleProdect(int price, string color) :Prodect(price), m_color(color) {};// 析构函数virtual ~AppleProdect() {};// 获取颜色string getColor() {return m_color;}
protected:// 颜色string m_color;
};// 抽象产品细分-香蕉
class BananaProdect : public Prodect
{
public:// 构造函数BananaProdect(int price) :Prodect(price) {};// 析构函数virtual ~BananaProdect() {};
};// 具体产品-中国苹果
class ChineseAppleProdect : public AppleProdect
{
public:// 构造函数ChineseAppleProdect(int price, string color) :AppleProdect(price, color) {cout << "获得了一个中国苹果。" << endl;};// 析构函数virtual ~ChineseAppleProdect() {cout << "吃掉了一个中国苹果。" << endl;};
};// 具体产品-美国苹果
class AmericanAppleProdect : public AppleProdect
{
public:// 构造函数AmericanAppleProdect(int price, string color) :AppleProdect(price, color) {cout << "获得了一个美国苹果。" << endl;};// 析构函数virtual ~AmericanAppleProdect() {cout << "吃掉了一个美国苹果。" << endl;};
};// 具体产品-中国香蕉
class ChineseBananaProdect : public BananaProdect
{
public:// 构造函数ChineseBananaProdect(int price) :BananaProdect(price) {cout << "获得了一个中国香蕉。" << endl;};// 析构函数virtual ~ChineseBananaProdect() {cout << "吃掉了一个中国香蕉。" << endl;};
};// 具体产品-美国香蕉
class AmericanBananaProdect : public BananaProdect
{
public:// 构造函数AmericanBananaProdect(int price) :BananaProdect(price) {cout << "获得了一个美国香蕉。" << endl;};// 析构函数virtual ~AmericanBananaProdect() {cout << "吃掉了一个美国香蕉。" << endl;};
};
//Factory.h
/****************************************************/
#pragma once
#include <iostream>
#include "Prodect.h"using namespace std;// 抽象工厂类
class Factory
{
public:// 获取苹果virtual Prodect* getApple() = 0;// 获取香蕉virtual Prodect* getBanana() = 0;
};// 具体工厂类-中国工厂
class ChineseFactory : public Factory
{
public:// 获取苹果virtual Prodect* getApple() {Prodect* prodect = new ChineseAppleProdect(5, "红");return prodect;}// 获取香蕉virtual Prodect* getBanana() {Prodect* prodect = new ChineseBananaProdect(3);return prodect;}
};// 具体工厂类-美国工厂
class AmericanFactory : public Factory
{
public:// 获取产品virtual Prodect* getApple() {Prodect* prodect = new AmericanAppleProdect(4, "黑");return prodect;}// 获取香蕉virtual Prodect* getBanana() {Prodect* prodect = new AmericanBananaProdect(2);return prodect;}
};
//main.cpp
/****************************************************/
#include <iostream>
#include <string>
#include "Factory.h"
#include "Prodect.h"using namespace std;int main()
{cout << "找到中国工厂。" << endl;Factory* factoryA = new ChineseFactory();Prodect *A = factoryA->getApple();Prodect *B = factoryA->getBanana();int applePrice = A->getPrice();int bananaPrice = B->getPrice();int sum = A->getPrice() + B->getPrice();cout << "苹果价格:" << applePrice << "元。" << endl;cout << "香蕉价格:" << bananaPrice << "元。" << endl;cout << "累计消费:" << sum << "元。" << endl;cout << "中国苹果" << dynamic_cast<AppleProdect*>(A)->getColor() << "色" << endl;delete A;delete B;delete factoryA;cout << "享用完毕。" << endl << endl;cout << "找到美国工厂。" << endl;Factory* factoryB = new AmericanFactory();Prodect *C = factoryB->getApple();Prodect *D = factoryB->getBanana();applePrice = C->getPrice();bananaPrice = D->getPrice();sum = C->getPrice() + D->getPrice();cout << "苹果价格:" << applePrice << "元。" << endl;cout << "香蕉价格:" << bananaPrice << "元。" << endl;cout << "累计消费:" << sum << "元。" << endl;cout << "美国苹果" << dynamic_cast<AppleProdect*>(C)->getColor() << "色" << endl;delete C;delete D;delete factoryB;cout << "享用完毕。不如China。" << endl;return 0;
}
程序结果如下。

在上述示例中,我们可以看到,这两个工厂都有同样的系列产品(苹果和香蕉),我想体验新的系列产品,只需要更换具体工厂即可。
三、总结
我尽可能用较通俗的话语和直观的代码例程,来表述我对抽象工厂模式的理解,或许有考虑不周到的地方,如果你有不同看法欢迎评论区交流!希望我举的例子能帮助你更好地理解抽象工厂模式。
如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!
相关文章:
设计模式之抽象工厂模式(C++)
作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 一、抽象工厂模式是什么? 抽象工厂模式是一种创建型的软件设计模式,该模式相当于升级版的工厂模式。 如果…...
Kotlin新手教程一(Kotlin简介及环境搭建)
目录一、 什么是Kotlin?二、为什么要使用Kotlin?三、使用IntelliJ IDEA搭建Kotlin四、Kotlin使用命令行编译一、 什么是Kotlin? Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,它也可以被编译成为 JavaScript 源代码&…...
【虚拟仿真】Unity3D打包WEBGL实现全屏切换
推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 今天实现Unity3D打包WEBGL后实现按钮点击全屏和退出 全屏的实现…...
java对象内存结构分析与大小计算
java对象内存结构Java对象保存在堆中时,由三部分组成:对象头(object header):包括了关于堆对象的布局、类型、GC状态、同步状态和标识哈希码的基本信息。所有java对象都有一个共同的对象头格实例数据(Insta…...
RabbitMQ学习(七):交换器
〇、前言在之前的内容中,我们创建了一个工作队列。我们假设的是工作队列背后,每个任务都恰好交付给一个消 费者(工作进程)。在今天的内容中,我们将做一些完全不同的事情——我们将消息传达给多个消费者。这种模式 称为 “发布/订阅”。为了说…...
cmd命令大全
文章目录变量输入输出逻辑命令符控制语句函数注释变量 在批处理中,变量全部是弱类型的,通常可以当做字符串处理 1.初始化定义 set varthis a var 2.获取变量值 %var% 3.链接 set varcat%var1%%var2% 4.截取 %var:~n,m% n是起点,m是长度&…...
Git的使用方法(保姆级)
一、安装git二、创建凭据 ①打开电脑的凭据管理器git:https://gitee.com是固定写法用户名、密码是你创建gitee的用户名、密码三、在gitee中创建一个仓库四、项目提交到仓库的方法①选择一个项目交由git管理按照步骤一中召唤小黑窗口输入 git init 就可以出现.git文件夹②右键选…...
TypeScript 学习之泛型
泛型使用 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型。就需要使用泛型。使用泛型就不会丢失类型信息,使用any会丢失类型信息。 function identity<T>(arg: T): T {return arg; }identity 添加了类型变量T, T 捕获用户传入的类型…...
新手学习node.js基础,node.js安装过程,node.js运行环境及javascript运行环境.
学习node.js1.什么是node.js?2.node.js中的javaScript运行环境3.node.js可以做什么?4. node.js学习思路5.node.js环境的安装6.如何在node.js中执行JavaScript代码1.什么是node.js? node.js是一个基于Chrome v8 引擎的JavaScript运行环境(后端) node.js官网 &…...
Maven的安装步骤(保姆级安装教程)
一、安装本地Maven 选择你需要的maven版本下载:官网下载传送门 我使用的是3.6.1版本:maven-3.6.1-bin.zip 二、安装 把下载好的maven压缩包解压到一个没有中文,空格或其他特殊字符的文件夹,如: 三、配置环境变量…...
Axure教程(一)——线框图与高保真原型图制作
前面我们学习了制作网页的技能,从这里开始我们来学习前端必备技能,就是用Axure来制作原型图,一方面我们能提前绘制出我们所需的页面,这在我们开发的时候能节省大量的时间,另一方面我们能通过给用户进行体验从而能够发现…...
wholeaked:一款能够追责数据泄露的文件共享工具
关于wholeaked wholeaked是一款功能强大的文件共享工具,该工具基于go语言开发,可以帮助广大系统管理员和安全研究人员在组织发生数据泄露的时候,迅速找出数据泄露的“始作俑者”。 wholeaked可以获取被共享的文件信息以及接收人列表&#x…...
动态规划——股票问题全解
引入 股票问题是一类动态问题,我们需要对其状态进行判定分析来得出答案 但其实,我们只需要抓住两个点,持有和不持有,在这两种状态下分析问题会简单清晰许多 下面将会对各个问题进行分析讲解,来解释什么是持有和不持…...
想做游戏开发要深入c/c++还是c#?
根据题主描述提三点建议: 先选择一个语言、选择一个引擎能入行确保精通一个及已入行的情况下,技多不压身不必想日后的”退而求其次“,现在的事情还没有开始做就想以后,太过虚无及功利了 下面是这三点的详细说明: 【选…...
【JMeter】【Mac】如何在Mac上打开JMeter
平常我们在Windows电脑里打开JMeter,只要双击JMeter.bat即可打开,那我换了Mac后,该怎么打开JMeter呢 一、命令行打开JMeter 1、打开JMeter路径 cd /Users/work/apache-jmeter-5.2/bin 2、运行JMeter sh jmeter 3、如果涉及到一些权限无…...
JAVA面试八股文一(并发与线程)
并发的三大特性原子性:cpu在执行过程不可以暂停然后再调度,不可以中断,要不全部执行完,要不全部不执行。可见性:当多个线程访问同一个变量时,一个线程改变了这个变量的值,其他线程能够立即看到修…...
C语言二级指针
目录一、1. 指针的作用2.二级指针3. 为什么要用二级指针一、 1. 指针的作用 内存的存储区就像一池湖水,数据就像池水里面的鱼,如果不用内存寻址的方式,那么当你找某个特定数据的时候,就相当于在一池湖水里找某一条叫做“张三”的…...
[java-面试]初级、中级、高级具备的技术栈和知识点
🌟1.java初级1. Java基础知识:语法、包装类、泛型、数据结构和继承,以及基础API。2. Java开发工具:如Eclipse,NetBeans,Maven等。3. Java Web开发技术:如Servlet,JSP,Str…...
「5」线性代数(期末复习)
🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀 目录 第四章 向量组的线性相关性 &5)向量空间 第五章 相似矩阵及二次型 &a…...
记一次20撸240的沙雕威胁情报提交(2019年老文)
0x01 起因 这是一篇沙雕文章,没什么技术含量,大家娱乐一下就好 前几个月,我的弟弟突然QQ给我发来了一条消息,说要买个QQ飞车的cdk,我作为一个通情达理的好哥哥,自然不好意思回绝,直接叫他发来…...
F_Record:让Photoshop绘画过程录制变得简单高效的轻量级插件
F_Record:让Photoshop绘画过程录制变得简单高效的轻量级插件 【免费下载链接】F_Record 一款用来录制绘画过程的轻量级PS插件 项目地址: https://gitcode.com/gh_mirrors/fr/F_Record 在数字艺术创作领域,每一笔笔触都承载着创作者的灵感与思考。…...
2026 年智慧工地排名榜单第一|山东建安物联科技有限公司
2026 年度智慧工地综合实力榜单正式揭晓,山东建安物联科技有限公司(大建安)凭借标准引领、技术实力与标杆项目,登顶全国榜首,成为行业公认的智慧工地领军企业。公司打造的中建八局烟台崆峒胜境项目,获评国家…...
nli-distilroberta-base前端集成案例:Vue.js构建智能文本分析界面
nli-distilroberta-base前端集成案例:Vue.js构建智能文本分析界面 1. 场景价值与方案概述 电商平台的客服系统每天需要处理大量用户咨询,其中很多问题都涉及产品参数的对比(如"这款手机电池容量比A型号大吗?"…...
YOLOv5 模型训练避坑大全:从数据集制作到解决 mAP 为 0 的常见报错
YOLOv5 模型训练避坑实战指南:从数据标注到调参优化的全流程解决方案 当你第一次成功运行YOLOv5的官方示例时,那种成就感可能让你误以为目标检测模型训练已经掌握。但现实往往很骨感——当换上自己的数据集后,各种报错接踵而至:显…...
Frida启动报错invalid address?手把手教你修复Android逆向工程环境
Frida启动报错invalid address?手把手教你修复Android逆向工程环境 当你满怀期待地启动Frida准备进行Android应用动态分析时,控制台突然抛出"invalid address"错误,那种感觉就像赛车手在起跑线上发现引擎故障。这个看似简单的错误信…...
Vue 3 + hls.js 实战:手把手教你打造一个能‘续命’的安防监控播放器
Vue 3 hls.js 打造安防级视频流播放器的"续命"秘籍 在安防监控、智慧城市等实时视频流应用场景中,网络抖动、服务中断、页面切换等问题常常导致视频播放中断,严重影响监控效果。本文将深入探讨如何基于Vue 3和hls.js构建一个具备"续命&q…...
从收音机到Wi-Fi:手把手复现经典小信号调谐放大器实验(附Multisim仿真文件)
从矿石收音机到5G射频前端:调谐放大器技术演进与Multisim仿真实践 上世纪二十年代,当业余无线电爱好者们用矿石和线圈组装出最简单的接收装置时,他们可能不会想到,这种基于LC谐振原理的选频技术会延续百年,成为现代无线…...
安卓虚拟摄像头:解锁手机摄像头的无限创意可能
安卓虚拟摄像头:解锁手机摄像头的无限创意可能 【免费下载链接】com.example.vcam 虚拟摄像头 virtual camera 项目地址: https://gitcode.com/gh_mirrors/co/com.example.vcam 想要在视频会议中展示精心准备的演示内容?还是希望在直播时使用定制…...
用NoneBot2给Lagrange机器人加buff:5个提升效率的插件开发技巧
用NoneBot2给Lagrange机器人加buff:5个提升效率的插件开发技巧 在智能对话机器人领域,NoneBot2与Lagrange的组合已经成为QQ生态中高效开发的黄金搭档。但当你已经掌握了基础功能开发后,如何让机器人更智能、更稳定、更能应对复杂场景…...
Alpamayo-R1-10B入门必看:VLA模型与传统端到端/模块化架构的本质差异
Alpamayo-R1-10B入门必看:VLA模型与传统端到端/模块化架构的本质差异 1. 引言:自动驾驶决策的十字路口 想象一下,你正在教一个新手司机开车。传统的方法有两种:一种是让他死记硬背所有交通规则和操作步骤(模块化&…...
