《设计模式》工厂模式
《设计模式》工厂模式
工厂模式又分为简单工厂(Simple Factory)、工厂方法(Factory Method)和抽象工厂(Abstract Factory)都是常用的创建型设计模式,它们的主要区别如下:
- 简单工厂:由一个工厂类根据传入的参数来决定创建哪一种产品类的对象。简单工厂适用于对象的创建比较简单,且客户端只需要知道传入的参数即可获取相应的对象的场景。
- 工厂方法:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法模式适用于需要一组相关对象的场景,客户端不需要知道它所使用的对象的具体类型,只需要知道创建对象的接口即可。
- 抽象工厂:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类。抽象工厂模式适用于需要一组相关的对象,这些对象之间有相互依赖关系,客户端不需要知道创建对象的具体实现细节,只需要知道创建对象的接口即可。
这三种工厂模式的优点及使用场景如下:
- 简单工厂的优点:易于实现、客户端调用方便。适用于工厂类负责创建的对象比较少的场景。
- 工厂方法的优点:符合开闭原则、可扩展性强。适用于需要一组相关对象,并且需要灵活地增加、替换和删除对象的场景。
- 抽象工厂的优点:符合开闭原则、封装性好、可扩展性强。适用于需要创建一组相互依赖、相关或不同类型的对象的场景。
综上所述,选择哪种工厂模式取决于具体的需求场景。如果只需要创建一种对象,则可以使用简单工厂;如果需要创建一组相关的对象,并且需要灵活地增加、替换和删除对象,则可以使用工厂方法;如果需要创建一组相互依赖、相关或不同类型的对象,则可以使用抽象工厂。
简单工厂
首先,定义一个抽象产品类 Product,它是由简单工厂模式负责创建的对象:
class Product {
public:virtual ~Product() {}virtual void operation() = 0;
};
接下来,定义具体产品类 ConcreteProductA 和 ConcreteProductB:
class ConcreteProductA : public Product {
public:void operation() {std::cout << "ConcreteProductA::operation()" << std::endl;}
};class ConcreteProductB : public Product {
public:void operation() {std::cout << "ConcreteProductB::operation()" << std::endl;}
};
这两个类继承了抽象产品类 Product,并实现了 operation 函数。ConcreteProductA 和 ConcreteProductB 是简单工厂模式创建的具体对象。
接下来,定义一个工厂类 Factory,它负责创建具体产品的对象:
class Factory {
public:Product* create_product(int type) {switch (type) {case 0:return new ConcreteProductA();case 1:return new ConcreteProductB();default:return nullptr;}}
};
这个工厂类有一个 create_product 函数,根据传入的类型返回具体产品的对象。在这个示例中,我们使用 switch 语句根据类型选择创建哪种具体产品。
最后,我们可以在主函数中使用简单工厂模式创建具体产品的对象:
int main() {Factory factory;Product* productA = factory.create_product(0);if (productA) {productA->operation();delete productA;}Product* productB = factory.create_product(1);if (productB) {productB->operation();delete productB;}Product* productC = factory.create_product(2);if (!productC) {std::cout << "Invalid product type!" << std::endl;}return 0;
}
在主函数中,我们先创建一个工厂对象,然后分别使用它创建 ConcreteProductA 和 ConcreteProductB 的对象,并调用它们的 operation 函数进行操作。最后,我们试图使用一个不存在的类型创建产品,这时候工厂类将返回 nullptr。
以上就是用 C++ 实现简单工厂模式的示例。
工厂方法
首先,定义一个抽象产品类 Product,它是由工厂方法模式负责创建的对象:
class Product {
public:virtual ~Product() {}virtual void operation() = 0;
};
接下来,定义具体产品类 ConcreteProductA 和 ConcreteProductB:
class ConcreteProductA : public Product {
public:void operation() {std::cout << "ConcreteProductA::operation()" << std::endl;}
};class ConcreteProductB : public Product {
public:void operation() {std::cout << "ConcreteProductB::operation()" << std::endl;}
};
这两个类继承了抽象产品类 Product,并实现了 operation 函数。ConcreteProductA 和 ConcreteProductB 是工厂方法模式创建的具体对象。
接下来,定义一个抽象工厂类 Factory,它声明一个工厂方法 create_product,由具体工厂类负责实现这个方法:
class Factory {
public:virtual ~Factory() {}virtual Product* create_product() = 0;
};
具体工厂类继承这个抽象工厂类,并实现 create_product 方法,用于创建具体产品的对象:
class ConcreteFactoryA : public Factory {
public:Product* create_product() {return new ConcreteProductA();}
};class ConcreteFactoryB : public Factory {
public:Product* create_product() {return new ConcreteProductB();}
};
这两个类继承了抽象工厂类 Factory,并实现了 create_product 方法。ConcreteFactoryA 和 ConcreteFactoryB 是工厂方法模式创建的具体工厂。
最后,我们可以在主函数中使用工厂方法模式创建具体产品的对象:
int main() {Factory* factoryA = new ConcreteFactoryA();Product* productA = factoryA->create_product();if (productA) {productA->operation();delete productA;}delete factoryA;Factory* factoryB = new ConcreteFactoryB();Product* productB = factoryB->create_product();if (productB) {productB->operation();delete productB;}delete factoryB;return 0;
}
在主函数中,我们先创建一个 ConcreteFactoryA 对象,然后使用它创建 ConcreteProductA 的对象,并调用它的 operation 函数进行操作。然后我们创建一个 ConcreteFactoryB 对象,使用它创建 ConcreteProductB 的对象,并调用它的 operation 函数进行操作。最后,我们删除创建的对象并销毁工厂对象。
以上就是用 C++ 实现工厂方法模式的示例。
抽象工厂
首先,定义一个抽象产品类 AbstractProductA 和 AbstractProductB,它们是由抽象工厂模式负责创建的对象:
class AbstractProductA {
public:virtual ~AbstractProductA() {}virtual void operationA() = 0;
};class AbstractProductB {
public:virtual ~AbstractProductB() {}virtual void operationB() = 0;
};
接下来,定义具体产品类 ConcreteProductA1、ConcreteProductA2、ConcreteProductB1 和 ConcreteProductB2:
class ConcreteProductA1 : public AbstractProductA {
public:void operationA() {std::cout << "ConcreteProductA1::operationA()" << std::endl;}
};class ConcreteProductA2 : public AbstractProductA {
public:void operationA() {std::cout << "ConcreteProductA2::operationA()" << std::endl;}
};class ConcreteProductB1 : public AbstractProductB {
public:void operationB() {std::cout << "ConcreteProductB1::operationB()" << std::endl;}
};class ConcreteProductB2 : public AbstractProductB {
public:void operationB() {std::cout << "ConcreteProductB2::operationB()" << std::endl;}
};
这四个类继承了抽象产品类 AbstractProductA 和 AbstractProductB,并实现了 operationA 和 operationB 函数。ConcreteProductA1、ConcreteProductA2、ConcreteProductB1 和 ConcreteProductB2 是抽象工厂模式创建的具体对象。
接下来,定义一个抽象工厂类 AbstractFactory,它声明一组工厂方法 createProductA 和 createProductB,由具体工厂类负责实现这些方法:
class AbstractFactory {
public:virtual ~AbstractFactory() {}virtual AbstractProductA* createProductA() = 0;virtual AbstractProductB* createProductB() = 0;
};
具体工厂类继承这个抽象工厂类,并实现 createProductA 和 createProductB 方法,用于创建具体产品的对象:
class ConcreteFactory1 : public AbstractFactory {
public:AbstractProductA* createProductA() {return new ConcreteProductA1();}AbstractProductB* createProductB() {return new ConcreteProductB1();}
};class ConcreteFactory2 : public AbstractFactory {
public:AbstractProductA* createProductA() {return new ConcreteProductA2();}AbstractProductB* createProductB() {return new ConcreteProductB2();}
};
这两个类继承了抽象工厂类 AbstractFactory,并实现了 createProductA 和 createProductB 方法。ConcreteFactory1 和 ConcreteFactory2 是抽象工厂模式创建的具体工厂。
最后,我们可以在主函数中使用抽象工厂模式创建具体产品的对象:
int main() {// 使用具体工厂1创建产品AbstractFactory* factory1 = new ConcreteFactory1();AbstractProductA* productA1 = factory1->createProductA();AbstractProductB* productB1 = factory1->createProductB();productA1->operationA();productB1->operationB();// 使用具体工厂2创建产品AbstractFactory* factory2 = new ConcreteFactory2();AbstractProductA* productA2 = factory2->createProductA();AbstractProductB* productB2 = factory2->createProductB();productA2->operationA();productB2->operationB();// 释放内存delete productA1;delete productB1;delete factory1;delete productA2;delete productB2;delete factory2;return 0;
}
运行结果如下:
ConcreteProductA1::operationA()
ConcreteProductB1::operationB()
ConcreteProductA2::operationA()
ConcreteProductB2::operationB()
这个示例实现了一个抽象工厂模式,其中抽象工厂类 AbstractFactory 声明了一组工厂方法,具体工厂类 ConcreteFactory1 和 ConcreteFactory2 实现了这些方法,用于创建具体产品的对象。而具体产品类 ConcreteProductA1、ConcreteProductA2、ConcreteProductB1 和 ConcreteProductB2 继承了抽象产品类 AbstractProductA 和 AbstractProductB,并实现了 operationA 和 operationB 函数,表示具体产品的操作。
以上就是用 C++ 实现抽象工厂模式的示例。
抽象工厂模式适用于需要一次性创建一系列相关或相互依赖的对象时,它能够提供一个简单的接口,用于创建这些对象,同时保证这些对象是相互兼容的。由于该模式要求所有具体产品都必须实现相同的接口,因此它提供了更好的灵活性和可扩展性。
相关文章:
《设计模式》工厂模式
《设计模式》工厂模式 工厂模式又分为简单工厂(Simple Factory)、工厂方法(Factory Method)和抽象工厂(Abstract Factory)都是常用的创建型设计模式,它们的主要区别如下: 简单工厂…...
JS - 原型对象、原型链是什么
一 阅读掘金 https://juejin.cn/post/7007416743215759373 https://juejin.cn/post/7007416743215759373 二 阅读掘金小册原型知识点 原型 涉及面试题:如何理解原型?如何理解原型链? 当我们创建一个对象时 let obj { age: 25 }࿰…...
STM32f103 CubeMX封装 led程序
本文代码使用 HAL 库。 文章目录前言一、LED 原理图二、CubeMX创建工程三、LED 相关函数1. 输出电平函数:2. 延时函数:3. 翻转电平函数:四、详细代码实验现象 :总结代码 源码:前言 从这篇文章开始,我们讲解…...
智慧教室系统--温湿度控制系统
随着科技的不断进步,智能化已经成为了各个行业的发展趋势,智慧教室作为未来教育的主流趋势之一,也将受益于这一趋势。而智慧教室中的温湿度控制系统是其中的重要组成部分,为了创造一个舒适、健康、安全的教学环境,智慧…...
只要一直向前定能到达远方,社科院与杜兰大学金融管理硕士项目为你注入动力
在人生这条道路上,我们很远的路要走,不管前方是否平坦,我们只要坚持前向,终将抵达远方。一路上我们付出很多,也收获很多。想要变得更强大,就要不断优化自身,积攒更多的能量,社科院与…...
Java性能-回收算法-Throughout回收算法
垃圾回收算法 理解Throughput回收器 回收器三个基本操作——回收 找到不使用的对象 释放内存 压缩堆碎片 Minor GC和Full GC,每个操作都会标记,释放和压缩对应的目标分代 [63.205s][info][gc,start ] GC(13) Pause Full (Ergonomics) [63.205s][info][…...
立项近7年,索尼产品经理分享PS VR2开发背后的故事
备受期待的索尼PS VR2终于正式发售,VR爱好者们终于有机会体验到《地平线:山之呼唤》等PS VR2独占的VR大作。近期,为了解PS VR2头显诞生背后的故事,外媒AV Watch采访到PS VR2的开发负责人Yasuo Takahashi,在本次采访中&…...
Kubernetes 如何通过ingress-nginx实现应用灰度发布?
在日常的工作中,我们会经常对应用进行发版升级,在互联网公司尤为频繁,主要是为了满足快速的业务发展。我们经常用到的发布方式有滚动更新、蓝绿发布、灰度发布。滚动更新:依次进行新旧替换,直到旧的全部被替换为止。蓝…...
华为OD机试 - 密室逃生游戏(Java) | 机试题+算法思路+考点+代码解析 【2023】
密室逃生游戏 小强增在参加《密室逃生》游戏,当前关卡要求找到符合给定 密码K(升序的不重复小写字母组成) 的箱子, 并给出箱子编号,箱子编号为 1~N 。 每个箱子中都有一个 字符串s ,字符串由大写字母、小写字母、数字、标点符号、空格组成, 需要在这些字符串中找到所有…...
redis的主从复制细节
文章目录复制机制的运作复制的一些事实master持久化关闭时,复制的安全性Redis复制是如何工作的只读性质的slave设置一个slave对master进行验证允许只写入N个附加的副本Redis如何处理过期键重新启动和故障转移后的部分同步复制机制的运作 master和slave的复制运作依…...
SparkSQL
第1章 SparkSQL 概述1.1 SparkSQL 是什么Spark SQL 是 Spark 用于结构化数据(structured data)处理的 Spark 模块。1.2 Hive and SparkSQLSparkSQL 的前身是 Shark,给熟悉 RDBMS 但又不理解 MapReduce 的技术人员提供快速上手的工具。Hive 是早期唯一运行在 Hadoop …...
Python|每日一练|栈|数组|字典树|数组|树|广度优先搜索|单选记录:逆波兰表达式求值|回文对|二叉树的层序遍历
1、逆波兰表达式求值(栈,数组) 根据 逆波兰表示法(https://baike.baidu.com/item/%E9%80%86%E6%B3%A2%E5%85%B0%E5%BC%8F/128437),求表达式的值。 有效的算符包括 、-、*、/ 。每个运算对象可以是整数,也可以是另一个…...
慧教室系统--远程控制系统
随着科技的不断进步,越来越多的教育机构开始使用智慧教室系统来提升教学效果和学生体验。智慧教室系统不仅可以自动化管理设备,还可以实现远程控制,帮助教师和学生更加便捷地使用教室设备。智慧教室系统作为一款领先的智慧教育解决方案&#…...
OSCP-课外1(http万能密码、hydra密码暴力破解http、代码审计、Win缓存区溢出)
目录 难度 主机发现&端口扫描 信息收集 万能密码 hydra密码暴力破解...
ELK日志分析--Logstash
Logstash简介 Logstash安装 测试运行 配置输入和输出 使用Geoip过滤器插件增强数据编辑 配置接收 Beats 的输入 1.Logstash简介 Logstash管道具有两个必需元素input和output,以及一个可选元素filter。输入插件使用来自源的数据,过滤器插件根据你的…...
Mysql插入数据从指定选项中随机选择、插入时间从指定范围随机生成、Navicat使用存储过程模拟插入测试数据
场景 Navicat通过存储过程批量插入mysql数据: Navicat通过存储过程批量插入mysql数据_霸道流氓气质的博客-CSDN博客 上面使用过Navicat借助存储过程批量插入数据。但是插入数据是固定的 insert语句,如果在本地开发时需要模拟插入一些随机数据(从指定…...
【基础算法】关于高精度计算的问题【很高位数数据的加减乘除(相关代码用C++实现)】
文章目录前言1.高精度加法2.高精度减法3.高精度乘法4.高精度除法写在最后前言 当我们在利用计算机进行一些计算时,可能会遇到这类问题 : 有些计算要求精度高,希望计算的数的位数可达几十位甚至几百位,虽然计算机的计算精度也算较…...
事理知识图谱
事理知识图谱能够有力第建模各类事件之间的演化关联关系为事理逻辑推理提供更好的数据基础。 事理图谱定义 事理知识图谱可以将文本中对事件以及事件之间的关系抽取并抽象出来,构建成一个有向图形式的事理知识库。在结构上,事理知识图谱是一个有向有环…...
多綫程之python爬蟲構建
目录多綫程定義簡介原理优点缺点优势代碼框架實現導包打印類爬蟲類構造方法獲取代理設置headers獲取新session獲取源代碼解析網頁解析子頁面保存數據綫程任務得到url啓動多綫程爬蟲總結多綫程 以下定義來自百度百科,看看就好沒仔細寫 定義 多线程(mul…...
【干货】Redis在Java开发中的基本使用和巧妙用法
Redis是一款高性能的内存数据结构存储系统,能够支持多种数据结构类型,如字符串、哈希、列表、集合、有序集合等,也能够支持高级功能,如事务、发布/订阅、Lua脚本等,具有高可用性、高并发性和可扩展性的优点。在Java开发…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!
目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...
如何配置一个sql server使得其它用户可以通过excel odbc获取数据
要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据,你需要完成以下配置步骤: ✅ 一、在 SQL Server 端配置(服务器设置) 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到:SQL Server 网络配…...
GraphQL 实战篇:Apollo Client 配置与缓存
GraphQL 实战篇:Apollo Client 配置与缓存 上一篇:GraphQL 入门篇:基础查询语法 依旧和上一篇的笔记一样,主实操,没啥过多的细节讲解,代码具体在: https://github.com/GoldenaArcher/graphql…...
macOS 终端智能代理检测
🧠 终端智能代理检测:自动判断是否需要设置代理访问 GitHub 在开发中,使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新,例如: fatal: unable to access https://github.com/ohmyzsh/oh…...
网页端 js 读取发票里的二维码信息(图片和PDF格式)
起因 为了实现在报销流程中,发票不能重用的限制,发票上传后,希望能读出发票号,并记录发票号已用,下次不再可用于报销。 基于上面的需求,研究了OCR 的方式和读PDF的方式,实际是可行的ÿ…...
