C++实现设计模式---抽象工厂模式 (Abstract Factory)
抽象工厂模式 (Abstract Factory)
抽象工厂模式 是一种创建型设计模式,提供一个接口,用于创建一组相关或互相依赖的对象,而无需指定它们的具体类。
意图
- 提供一个创建一组相关对象的接口,而无需指定它们的具体类。
- 解决产品对象之间的相互依赖问题,使得一组对象能协同工作。
使用场景
- 需要创建一组相关对象:
- 如 GUI 程序中,窗口、按钮、菜单等需要统一的外观风格。
- 需要保证对象之间的兼容性:
- 如游戏开发中,不同种族的士兵和建筑需要互相匹配。
- 需要隐藏具体实现:
- 客户端代码只依赖于产品接口,具体实现被封装。
参与者角色
- 抽象工厂 (Abstract Factory)
- 声明一组用于创建相关对象的接口。
- 具体工厂 (Concrete Factory)
- 实现抽象工厂的接口,创建具体的产品。
- 抽象产品 (Abstract Product)
- 定义所有产品的公共接口。
- 具体产品 (Concrete Product)
- 实现抽象产品的接口,为具体工厂生产的对象。
示例代码
以下示例展示了如何使用抽象工厂模式为不同操作系统创建相关的 GUI 组件(按钮和窗口)。
#include <iostream>
#include <memory>// 抽象产品 A: 按钮
class Button {
public:virtual void render() const = 0;virtual ~Button() {}
};// 具体产品 A1: Windows 按钮
class WindowsButton : public Button {
public:void render() const override {std::cout << "Rendering Windows Button" << std::endl;}
};// 具体产品 A2: Mac 按钮
class MacButton : public Button {
public:void render() const override {std::cout << "Rendering Mac Button" << std::endl;}
};// 抽象产品 B: 窗口
class Window {
public:virtual void render() const = 0;virtual ~Window() {}
};// 具体产品 B1: Windows 窗口
class WindowsWindow : public Window {
public:void render() const override {std::cout << "Rendering Windows Window" << std::endl;}
};// 具体产品 B2: Mac 窗口
class MacWindow : public Window {
public:void render() const override {std::cout << "Rendering Mac Window" << std::endl;}
};// 抽象工厂
class GUIFactory {
public:virtual std::unique_ptr<Button> createButton() const = 0;virtual std::unique_ptr<Window> createWindow() const = 0;virtual ~GUIFactory() {}
};// 具体工厂 1: Windows 工厂
class WindowsFactory : public GUIFactory {
public:std::unique_ptr<Button> createButton() const override {return std::make_unique<WindowsButton>();}std::unique_ptr<Window> createWindow() const override {return std::make_unique<WindowsWindow>();}
};// 具体工厂 2: Mac 工厂
class MacFactory : public GUIFactory {
public:std::unique_ptr<Button> createButton() const override {return std::make_unique<MacButton>();}std::unique_ptr<Window> createWindow() const override {return std::make_unique<MacWindow>();}
};// 主函数
int main() {// 选择具体工厂std::unique_ptr<GUIFactory> factory = std::make_unique<WindowsFactory>();// 使用工厂创建产品auto button = factory->createButton();auto window = factory->createWindow();button->render(); // 输出:Rendering Windows Buttonwindow->render(); // 输出:Rendering Windows Window// 切换到另一种具体工厂factory = std::make_unique<MacFactory>();button = factory->createButton();window = factory->createWindow();button->render(); // 输出:Rendering Mac Buttonwindow->render(); // 输出:Rendering Mac Windowreturn 0;
}
代码解析
1. 抽象产品类
定义了产品的公共接口,确保产品类型的一致性:
class Button {
public:virtual void render() const = 0;virtual ~Button() {}
};
2. 具体产品类
实现了抽象产品接口,并提供具体功能:
class WindowsButton : public Button {
public:void render() const override {std::cout << "Rendering Windows Button" << std::endl;}
};
3. 抽象工厂
定义了创建一组相关产品的接口:
class GUIFactory {
public:virtual std::unique_ptr<Button> createButton() const = 0;virtual std::unique_ptr<Window> createWindow() const = 0;virtual ~GUIFactory() {}
};
4. 具体工厂
实现了抽象工厂接口,负责生产具体的产品:
class WindowsFactory : public GUIFactory {
public:std::unique_ptr<Button> createButton() const override {return std::make_unique<WindowsButton>();}std::unique_ptr<Window> createWindow() const override {return std::make_unique<WindowsWindow>();}
};
5. 主函数
客户端代码通过工厂接口创建产品,无需知道具体产品的实现:
std::unique_ptr<GUIFactory> factory = std::make_unique<WindowsFactory>();
auto button = factory->createButton();
auto window = factory->createWindow();
button->render();
window->render();
优缺点
优点
- 解耦:客户端代码只依赖抽象工厂和抽象产品,与具体实现无关。
- 保证产品一致性:抽象工厂确保一组对象是兼容的。
- 扩展性强:可以通过新增具体工厂扩展系统。
缺点
- 增加复杂性:每增加一组产品需要新增抽象类和具体类。
- 灵活性受限:对现有产品结构的修改可能需要更新所有工厂。
适用场景
- 跨平台开发:如为不同操作系统设计统一的 GUI。
- 产品族设计:如游戏中不同种族的士兵和建筑需要互相匹配。
- 动态扩展产品族:如增加新的平台支持。
改进与扩展
-
结合配置文件
动态选择具体工厂,根据运行时条件决定产品族的创建:std::unique_ptr<GUIFactory> factory; if (platform == "Windows") {factory = std::make_unique<WindowsFactory>(); } else {factory = std::make_unique<MacFactory>(); }
-
引入依赖注入框架
通过依赖注入简化工厂选择的逻辑,使得代码更易于维护和测试。
总结
抽象工厂模式通过提供一个接口,用于创建一组相关对象,实现了创建逻辑的集中化和产品族之间的兼容性。
它适用于需要跨平台开发或产品族设计的场景。
相关文章:

C++实现设计模式---抽象工厂模式 (Abstract Factory)
抽象工厂模式 (Abstract Factory) 抽象工厂模式 是一种创建型设计模式,提供一个接口,用于创建一组相关或互相依赖的对象,而无需指定它们的具体类。 意图 提供一个创建一组相关对象的接口,而无需指定它们的具体类。解决产品对象之…...

K8S开启/关闭审计日志
K8S默认禁用审计 开启/关闭 k8s 审计日志 默认 Kubernetes 集群不会输出审计日志信息。通过以下配置,可以开启 Kubernetes 的审计日志功能。 准备审计日志的 Policy 文件配置 API 服务器,开启审计日志重启并验证 准备审计日志 Policy 文件 apiVersio…...

css盒子水平垂直居中
目录 1采用flex弹性布局: 2子绝父相margin:负值: 3.子绝父相margin:auto: 4子绝父相transform: 5通过伪元素 6table布局 7grid弹性布局 文字 水平垂直居中链接:文字水平垂直居中-CSDN博客 以下为盒子…...

px、em 和 rem 的区别:深入理解 CSS 中的单位
文章目录 前言一、px - 像素 (Pixel)二、em - 相对父元素字体大小 (Ems)三、rem - 相对于根元素字体大小 (Root Ems)四、综合比较结语 前言 在CSS中,px、em和rem是三种用于定义尺寸(如宽度、高度、边距、填充等)的长度单位。它们各自有不同的…...

基于STM32设计的粮食仓库(粮仓)环境监测系统
一、前言 1.1 项目开发背景 随着现代农业的发展和粮食储存规模的扩大,粮仓环境的智能化监控需求日益增长。传统的粮仓管理方式通常依赖人工检测和定期巡查,效率低下且容易出现疏漏,无法及时发现潜在问题,可能导致粮食受潮、霉变…...

【后端面试总结】tls中.crt和.key的关系
tls中.crt和.key的关系 引言 在现代网络通信中,特别是基于SSL/TLS协议的加密通信中,.crt和.key文件扮演着至关重要的角色。这两个文件分别代表了数字证书和私钥,是确保通信双方身份认证和数据传输安全性的基石。本文旨在深入探讨TLS中.crt和…...

日拱一卒(20)——leetcode学习记录:大小为 K 且平均值大于等于阈值的子数组数目
一、题目 给定数组,统计数组中长度为k的子数组且该子数组的平均值大于threshold的数量 二、思路 滑动窗思路,计算长度为k的滑动窗的平均值,关键点在于,每滑动一次,只需要去掉头增加尾,而不需要重新全部计…...

项目练习:若依管理系统字典功能-Vue前端部分
文章目录 一、情景说明二、若依Vue相关代码及配置1、utils代码2、components组件3、api接口代码4、Vuex配置5、main.js配置 三、使用方法1、html部分2、js部分 一、情景说明 我们在做web系统的时候,肯定会遇到一些常量选择场景。 比如,性别:…...

apache-skywalking-apm-10.1.0使用
apache-skywalking-apm-10.1.0使用 本文主要介绍如何使用apache-skywalking-apm-10.1.0,同时配合elasticsearch-8.17.0-windows-x86_64来作为存储 es持久化数据使用。 步骤如下: 一、下载elasticsearch-8.17.0-windows-x86_64 1、下载ES(elasticsear…...

计算机视觉算法实战——视频分析(Video Analysis)
✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ 视频分析是计算机视觉中的一个重要领域,旨在从视频数据中提取有用的信息&…...

全网首发:编译libssh,产生类似undefined reference to `EVP_aes_256_ctr@OPENSSL_1_1_0‘的大量错误
具体错误 前面和后面的: /opt/linux/x86-arm/aarch64-mix210-linux/host_bin/../lib/gcc/aarch64-linux-gnu/7.3.0/../../../../aarch64-linux-gnu/bin/ld: warning: libcrypto.so.1.1, needed by ../lib/libssh.so.4.10.1, not found (try using -rpath or -rpat…...

用python实战excel和word自动化
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 python实现excel和word自动化--批量处理 前言--需求快要期末了需要,提交一个年级的学生成绩数据,也就是几百份。当前我们收集了一份excel表格…...

【云计算】OpenStack云计算平台
OpenStack云计算平台框架搭建 1.先换源 先换成阿里源: curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo 2.安装框架 yum -y install centos-release-openstack-train 3.安装客户端 yum -y install python-openstackclient 但…...

好用的php商城源码有哪些?
选择一个优秀的商城工具,能更好地帮助大家建立一个好用的商城系统。目前比较流行的都是开源PHP商城系统,那么现实中都有哪些好用的PHP商城源码值得推荐呢?下面就带大家一起来了解一下。 1.TigShop 【推荐指数】:★★★★★☆ 【推…...

docker安装Nginx UI
开源地址:nginx-ui/README-zh_CN.md at dev 0xJacky/nginx-ui GitHub docker run -dit \ --namenginx-ui \ --restartalways \ -e TZAsia/Shanghai \ -v /Users/xiaoping/docker/appdata/nginx:/etc/nginx \ -v /Users/xiaoping/docker/appdata/nginx-ui:/etc/ng…...

为深度学习创建PyTorch张量 - 最佳选项
为深度学习创建PyTorch张量 - 最佳选项 正如我们所看到的,PyTorch张量是torch.Tensor PyTorch类的实例。张量的抽象概念与PyTorch张量之间的区别在于,PyTorch张量为我们提供了一个可以在代码中操作的具体实现。 在上一篇文章中,我们看到了…...

详解数据增强中的平移shft操作
Shift 平移是指在数据增强(data augmentation)过程中,通过对输入图像或目标进行位置偏移(平移),让目标在图像中呈现出不同的位置。Shift 平移的目的是增加训练数据的多样性,从而提高模型对目标在…...

CCLINKIE转ModbusTCP网关,助机器人“掀起”工业智能的“惊涛骇浪”
以下是一个稳联技术CCLINKIE转ModbusTCP网关(WL-CCL-MTCP)连接三菱PLC与机器人的配置案例:设备与软件准备设备:稳联技术WL-CCL-MTCP网关、三菱FX5UPLC、支持ModbusTCP协议的机器人、网线等。 稳联技术ModbusTCP转CCLINKIE网关&…...

类型安全与代码复用的C# 泛型
一、引言:泛型 ——C# 编程的神奇钥匙 在 C# 编程的广袤天地里,泛型宛如一把神奇钥匙,能够开启高效、灵活且安全的代码之门🚪。 想象一下,你是一位经验丰富的建筑师,要建造各种各样的房子🏠。…...

卷积神经05-GAN对抗神经网络
卷积神经05-GAN对抗神经网络 使用Python3.9CUDA11.8Pytorch实现一个CNN优化版的对抗神经网络 简单的GAN图片生成 CNN优化后的图片生成 优化模型代码对比 0-核心逻辑脉络 1)Anacanda使用CUDAPytorch2)使用本地MNIST进行手写图片训练3)…...

vscode使用Marscode编程助手
下载 vscode 在插件里下载Marscode编程助手 插件完成 在这里点击安装,点击后这里出现AI编程插件。...

网络分析仪测试S参数
S参数的测试 一:S参数的定义 S参数(Scattering Parameters,散射参数)是一个表征器件在射频信号激励下的电气行为的工具,它以输入信号、输出信号为元素的矩阵来表现DUT的“传输”和“散射”效应,输入、输出…...

docker mysql5.7如何设置不区分大小写
环境 docker部署,镜像是5.7,操作系统是centos 操作方式 mysql 配置文件是放在 /etc/mysql/mysql.conf.d/mysqld.cnf, vim /etc/mysql/mysql.conf.d/mysqld.cnf lower_case_table_names1 重启mysql容器 验证 SHOW VARIABLES LIKE low…...

【1】Word:邀请函
目录 题目 文字解析 流程 题目 文字解析 考生文件夹☞Word.docx☞一定要用ms打开,wps打开作答无效☞作答完毕,F12或者手动另存为(考生文件夹:路径文件名) 注意:一定要检查,很有可能你前面步…...

【gin】中间件使用之jwt身份认证和Cors跨域,go案例
Gin-3 中间件编程及 JWT 身份认证 1. Gin 中间件概述 中间件是处理 HTTP 请求的函数,可以在请求到达路由处理函数之前或之后对请求进行处理。 在 Gin 框架中,中间件常用于处理日志记录、身份验证、权限控制等功能。 router : gin.Default() router.Us…...

【JAVA实战】@FeignClient注解类通用请求封装
背景 最近在编写多个系统数据集成过程中,经常会使用到FeignClient注解标记一个类,类里面编写很多请求方法,如果第三方系统有非常多的URL请求,每个方法对应一个URL请求,那么这个类就会非常的庞大,是否有一种…...

[c语言日寄]精英怪:三子棋(tic-tac-toe)3命慢通[附免费源码]
哈喽盆友们,今天带来《c语言》游戏中[三子棋boss]速通教程!我们的目标是一边编写博文,一边快速用c语言实现三子棋游戏。准备好瓜子,我们计时开始! 前期规划 在速通中,我们必须要有清晰的前期规划…...

GORM(Go语言数据交互库)
GORM(Go ORM,即对象关系映射)是Go语言中非常流行且功能强大的数据库交互库。它简化了与关系型数据库的交互过程,提供了丰富的API来处理各种数据库操作。下面将详细介绍GORM的功能、使用方法和一些高级特性。 1. 安装 首先&#…...

Redis主从同步是怎么实现的?
Redis主从同步是怎么实现的? 主从节点建立连接后,从节点会进行判断: 1.如果这是从节点之前没有同步过数据 属于初次复制,会进行全量重同步,那么从节点会向主节点发送PSYNC?-1 命令,请求主节点进行全量重…...

Flutter中Get.snackbar避免重复显示的实现
在pubspec.yaml中引入依赖框架。 #GetX依赖注解get: ^4.6.5创建一个SnackBarManager管理类去管理每个提示框。 import package:get/get.dart; import package:flutter/material.dart;class SnackBarManager {factory SnackBarManager() > instance;static final SnackBarMa…...