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

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

作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

一、抽象工厂模式是什么?

       抽象工厂模式是一种创建型的软件设计模式,该模式相当于升级版的工厂模式。

       如果说工厂模式对应一个产品系列,那抽象工厂就对应了多个产品系列。比如工厂模式中有鞋子、衣服和裤子可以生产,那抽象工厂模式就会衍生出耐克工厂和阿迪工厂,这两个工厂分别生产各自品牌的鞋子、衣服和裤子,客户只需要选择具体工厂和想要的产品即可。如果想要替换产品系列,也只需要将具体工厂切换为别的品牌就行了。

       抽象工厂模式的优点:

  1. 具体类分离。具体产品类在具体工厂的实现中进行了分离和归类。
  2. 易于更换产品族。当客户想要改变整个产品族时,只需要切换具体工厂即可。
  3. 利于产品一致性。当产品族的各个产品需要在一起执行时,抽象工厂可以确保客户只操作同系列产品,而不会进行跨品牌的组合。

      抽象工厂模式的缺点:

  1. 不利于添加新种类产品。每加一个新的种类,如多一个项链类型的产品,那每一个具体工厂都要进行代码的扩展,且破坏了原先规定的结构,违反了开闭原则。

二、抽象工厂模式

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++)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 一、抽象工厂模式是什么&#xff1f; 抽象工厂模式是一种创建型的软件设计模式&#xff0c;该模式相当于升级版的工厂模式。 如果…...

Kotlin新手教程一(Kotlin简介及环境搭建)

目录一、 什么是Kotlin&#xff1f;二、为什么要使用Kotlin&#xff1f;三、使用IntelliJ IDEA搭建Kotlin四、Kotlin使用命令行编译一、 什么是Kotlin&#xff1f; Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言&#xff0c;它也可以被编译成为 JavaScript 源代码&…...

【虚拟仿真】Unity3D打包WEBGL实现全屏切换

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 今天实现Unity3D打包WEBGL后实现按钮点击全屏和退出 全屏的实现…...

java对象内存结构分析与大小计算

java对象内存结构Java对象保存在堆中时&#xff0c;由三部分组成&#xff1a;对象头&#xff08;object header&#xff09;&#xff1a;包括了关于堆对象的布局、类型、GC状态、同步状态和标识哈希码的基本信息。所有java对象都有一个共同的对象头格实例数据&#xff08;Insta…...

RabbitMQ学习(七):交换器

〇、前言在之前的内容中&#xff0c;我们创建了一个工作队列。我们假设的是工作队列背后&#xff0c;每个任务都恰好交付给一个消 费者(工作进程)。在今天的内容中&#xff0c;我们将做一些完全不同的事情——我们将消息传达给多个消费者。这种模式 称为 “发布/订阅”。为了说…...

cmd命令大全

文章目录变量输入输出逻辑命令符控制语句函数注释变量 在批处理中&#xff0c;变量全部是弱类型的&#xff0c;通常可以当做字符串处理 1.初始化定义 set varthis a var 2.获取变量值 %var% 3.链接 set varcat%var1%%var2% 4.截取 %var:~n,m% n是起点&#xff0c;m是长度&…...

Git的使用方法(保姆级)

一、安装git二、创建凭据 ①打开电脑的凭据管理器git:https://gitee.com是固定写法用户名、密码是你创建gitee的用户名、密码三、在gitee中创建一个仓库四、项目提交到仓库的方法①选择一个项目交由git管理按照步骤一中召唤小黑窗口输入 git init 就可以出现.git文件夹②右键选…...

TypeScript 学习之泛型

泛型使用 组件不仅能够支持当前的数据类型&#xff0c;同时也能支持未来的数据类型。就需要使用泛型。使用泛型就不会丢失类型信息&#xff0c;使用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可以做什么&#xff1f;4. node.js学习思路5.node.js环境的安装6.如何在node.js中执行JavaScript代码1.什么是node.js? node.js是一个基于Chrome v8 引擎的JavaScript运行环境(后端) node.js官网 &…...

Maven的安装步骤(保姆级安装教程)

一、安装本地Maven 选择你需要的maven版本下载&#xff1a;官网下载传送门 我使用的是3.6.1版本&#xff1a;maven-3.6.1-bin.zip 二、安装 把下载好的maven压缩包解压到一个没有中文&#xff0c;空格或其他特殊字符的文件夹&#xff0c;如&#xff1a; 三、配置环境变量…...

Axure教程(一)——线框图与高保真原型图制作

前面我们学习了制作网页的技能&#xff0c;从这里开始我们来学习前端必备技能&#xff0c;就是用Axure来制作原型图&#xff0c;一方面我们能提前绘制出我们所需的页面&#xff0c;这在我们开发的时候能节省大量的时间&#xff0c;另一方面我们能通过给用户进行体验从而能够发现…...

wholeaked:一款能够追责数据泄露的文件共享工具

关于wholeaked wholeaked是一款功能强大的文件共享工具&#xff0c;该工具基于go语言开发&#xff0c;可以帮助广大系统管理员和安全研究人员在组织发生数据泄露的时候&#xff0c;迅速找出数据泄露的“始作俑者”。 wholeaked可以获取被共享的文件信息以及接收人列表&#x…...

动态规划——股票问题全解

引入 股票问题是一类动态问题&#xff0c;我们需要对其状态进行判定分析来得出答案 但其实&#xff0c;我们只需要抓住两个点&#xff0c;持有和不持有&#xff0c;在这两种状态下分析问题会简单清晰许多 下面将会对各个问题进行分析讲解&#xff0c;来解释什么是持有和不持…...

想做游戏开发要深入c/c++还是c#?

根据题主描述提三点建议&#xff1a; 先选择一个语言、选择一个引擎能入行确保精通一个及已入行的情况下&#xff0c;技多不压身不必想日后的”退而求其次“&#xff0c;现在的事情还没有开始做就想以后&#xff0c;太过虚无及功利了 下面是这三点的详细说明&#xff1a; 【选…...

【JMeter】【Mac】如何在Mac上打开JMeter

平常我们在Windows电脑里打开JMeter&#xff0c;只要双击JMeter.bat即可打开&#xff0c;那我换了Mac后&#xff0c;该怎么打开JMeter呢 一、命令行打开JMeter 1、打开JMeter路径 cd /Users/work/apache-jmeter-5.2/bin 2、运行JMeter sh jmeter 3、如果涉及到一些权限无…...

JAVA面试八股文一(并发与线程)

并发的三大特性原子性&#xff1a;cpu在执行过程不可以暂停然后再调度&#xff0c;不可以中断&#xff0c;要不全部执行完&#xff0c;要不全部不执行。可见性&#xff1a;当多个线程访问同一个变量时&#xff0c;一个线程改变了这个变量的值&#xff0c;其他线程能够立即看到修…...

C语言二级指针

目录一、1. 指针的作用2.二级指针3. 为什么要用二级指针一、 1. 指针的作用 内存的存储区就像一池湖水&#xff0c;数据就像池水里面的鱼&#xff0c;如果不用内存寻址的方式&#xff0c;那么当你找某个特定数据的时候&#xff0c;就相当于在一池湖水里找某一条叫做“张三”的…...

[java-面试]初级、中级、高级具备的技术栈和知识点

&#x1f31f;1.java初级1. Java基础知识&#xff1a;语法、包装类、泛型、数据结构和继承&#xff0c;以及基础API。2. Java开发工具&#xff1a;如Eclipse&#xff0c;NetBeans&#xff0c;Maven等。3. Java Web开发技术&#xff1a;如Servlet&#xff0c;JSP&#xff0c;Str…...

「5」线性代数(期末复习)

&#x1f680;&#x1f680;&#x1f680;大家觉不错的话&#xff0c;就恳求大家点点关注&#xff0c;点点小爱心&#xff0c;指点指点&#x1f680;&#x1f680;&#x1f680; 目录 第四章 向量组的线性相关性 &5&#xff09;向量空间 第五章 相似矩阵及二次型 &a…...

记一次20撸240的沙雕威胁情报提交(2019年老文)

0x01 起因 这是一篇沙雕文章&#xff0c;没什么技术含量&#xff0c;大家娱乐一下就好 前几个月&#xff0c;我的弟弟突然QQ给我发来了一条消息&#xff0c;说要买个QQ飞车的cdk&#xff0c;我作为一个通情达理的好哥哥&#xff0c;自然不好意思回绝&#xff0c;直接叫他发来…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

Ubuntu Cursor升级成v1.0

0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开&#xff0c;快捷键也不好用&#xff0c;当看到 Cursor 升级后&#xff0c;还是蛮高兴的 1. 下载 Cursor 下载地址&#xff1a;https://www.cursor.com/cn/downloads 点击下载 Linux (x64) &#xff0c;…...

如何配置一个sql server使得其它用户可以通过excel odbc获取数据

要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据&#xff0c;你需要完成以下配置步骤&#xff1a; ✅ 一、在 SQL Server 端配置&#xff08;服务器设置&#xff09; 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到&#xff1a;SQL Server 网络配…...

基于开源AI智能名片链动2 + 1模式S2B2C商城小程序的沉浸式体验营销研究

摘要&#xff1a;在消费市场竞争日益激烈的当下&#xff0c;传统体验营销方式存在诸多局限。本文聚焦开源AI智能名片链动2 1模式S2B2C商城小程序&#xff0c;探讨其在沉浸式体验营销中的应用。通过对比传统品鉴、工厂参观等初级体验方式&#xff0c;分析沉浸式体验的优势与价值…...

ArcPy扩展模块的使用(3)

管理工程项目 arcpy.mp模块允许用户管理布局、地图、报表、文件夹连接、视图等工程项目。例如&#xff0c;可以更新、修复或替换图层数据源&#xff0c;修改图层的符号系统&#xff0c;甚至自动在线执行共享要托管在组织中的工程项。 以下代码展示了如何更新图层的数据源&…...

6.9本日总结

一、英语 复习默写list11list18&#xff0c;订正07年第3篇阅读 二、数学 学习线代第一讲&#xff0c;写15讲课后题 三、408 学习计组第二章&#xff0c;写计组习题 四、总结 明天结束线代第一章和计组第二章 五、明日计划 英语&#xff1a;复习l默写sit12list17&#…...

Linux入门课的思维导图

耗时两周&#xff0c;终于把慕课网上的Linux的基础入门课实操、总结完了&#xff01; 第一次以Blog的形式做学习记录&#xff0c;过程很有意思&#xff0c;但也很耗时。 课程时长5h&#xff0c;涉及到很多专有名词&#xff0c;要去逐个查找&#xff0c;以前接触过的概念因为时…...