【C/C++】设计模式之工厂模式:从简单到抽象的演进

文章目录

  • 设计模式之工厂模式:从简单到抽象的演进
    • 1 “工厂”模式分类
      • 1.1 简单工厂(Simple Factory)
      • 1.2 工厂方法(Factory Method)
      • 1.3 抽象工厂(Abstract Factory)
    • 2 分析
    • 3 总结对比

设计模式之工厂模式:从简单到抽象的演进

1 “工厂”模式分类

“工厂”模式在设计模式中是一个重要的创建型模式,它可以分为以下几类:

1.1 简单工厂(Simple Factory)

【不是 GOF 23 种经典设计模式之一】

  • 特点:由一个工厂类根据传入参数决定创建哪种产品类。
  • 缺点:违反开闭原则,每新增一个产品就要修改工厂逻辑。
  • 适用场景:产品种类不多,变化不频繁。
#include <iostream>
#include <memory>
#include <string>class Shape {
public:virtual void draw() = 0;virtual ~Shape() = default;
};class Circle : public Shape {
public:void draw() override {std::cout << "Drawing Circle\n";}
};class Rectangle : public Shape {
public:void draw() override {std::cout << "Drawing Rectangle\n";}
};class ShapeFactory {
public:static std::unique_ptr<Shape> createShape(const std::string& type) {if (type == "circle") return std::make_unique<Circle>();if (type == "rectangle") return std::make_unique<Rectangle>();return nullptr;}
};// 使用
int main() {auto shape = ShapeFactory::createShape("circle");if (shape) shape->draw();return 0;
}

1.2 工厂方法(Factory Method)

【GOF 经典设计模式之一】

  • 特点:定义一个用于创建对象的接口,让子类决定实例化哪一个类。

  • 优点:符合开闭原则。

  • 适用场景:产品种类较多,或需要定制化创建流程。

  • 与简单工厂区别:每个产品对应一个具体工厂类;新增产品只需新增一个工厂类,符合开闭原则。

#include <iostream>
#include <memory>class Shape {
public:virtual void draw() = 0;virtual ~Shape() = default;
};class Circle : public Shape {
public:void draw() override {std::cout << "Drawing Circle\n";}
};// 工厂基类
class ShapeFactory {
public:virtual std::unique_ptr<Shape> createShape() = 0;virtual ~ShapeFactory() = default;
};// 工厂子类
class CircleFactory : public ShapeFactory {
public:std::unique_ptr<Shape> createShape() override {return std::make_unique<Circle>();}
};// 使用
int main() {std::unique_ptr<ShapeFactory> factory = std::make_unique<CircleFactory>();auto shape = factory->createShape();shape->draw();return 0;
}

1.3 抽象工厂(Abstract Factory)

【GOF 经典设计模式之一】

  • 特点:提供一个接口,用于创建多个相关或依赖的对象族。

  • 优点:适合产品之间存在关系(如 UI 控件风格:Windows vs Mac)。

  • 适用场景:需要创建多个相互关联的产品族,而不需要指定具体类。

  • 与前面工厂模式的区别:创建一组相关产品(产品族);适用于系统需要生产多个产品系列(如不同平台的 UI)。

#include <iostream>
#include <memory>// 抽象产品
class Button {
public:virtual void paint() = 0;virtual ~Button() = default;
};class Checkbox {
public:virtual void toggle() = 0;virtual ~Checkbox() = default;
};// Windows 产品
class WindowsButton : public Button {
public:void paint() override {std::cout << "Windows Button\n";}
};class WindowsCheckbox : public Checkbox {
public:void toggle() override {std::cout << "Windows Checkbox toggled\n";}
};// Mac 产品
class MacButton : public Button {
public:void paint() override {std::cout << "Mac Button\n";}
};class MacCheckbox : public Checkbox {
public:void toggle() override {std::cout << "Mac Checkbox toggled\n";}
};// 抽象工厂
class GUIFactory {
public:virtual std::unique_ptr<Button> createButton() = 0;virtual std::unique_ptr<Checkbox> createCheckbox() = 0;virtual ~GUIFactory() = default;
};// Windows 工厂
class WindowsFactory : public GUIFactory {
public:std::unique_ptr<Button> createButton() override {return std::make_unique<WindowsButton>();}std::unique_ptr<Checkbox> createCheckbox() override {return std::make_unique<WindowsCheckbox>();}
};// Mac 工厂
class MacFactory : public GUIFactory {
public:std::unique_ptr<Button> createButton() override {return std::make_unique<MacButton>();}std::unique_ptr<Checkbox> createCheckbox() override {return std::make_unique<MacCheckbox>();}
};// 使用
int main() {std::unique_ptr<GUIFactory> factory = std::make_unique<WindowsFactory>();auto button = factory->createButton();auto checkbox = factory->createCheckbox();button->paint();checkbox->toggle();return 0;
}

2 分析

简单工厂模式通过一个固定工厂类根据参数决定创建哪个单一产品对象,它是一种集中式、非继承的设计;

工厂方法模式将创建逻辑交由各自的工厂子类实现,满足开闭原则,适用于单一产品类的灵活扩展;

抽象工厂模式在工厂方法的基础上增加了“产品族(多个相关产品)”的抽象接口,统一生产一组彼此关联的产品,实现更高级别的解耦和扩展。

设计模式核心思想是否使用继承
简单工厂使用一个类集中管理对象创建(if-else
工厂方法为每个产品定义一个创建类(工厂子类)
抽象工厂为一组产品族提供统一创建接口

辅助记忆方法:
简单工厂 = 统一超市收银台:你买啥,告诉我商品代码,我帮你找。
工厂方法 = 各品牌有独立专卖店:你要耐克去耐克店,要阿迪去阿迪店。
抽象工厂 = 同一品牌店提供一整套商品组合(鞋、衣服、帽子):Nike-全套,Adidas-全套。


3 总结对比

模式是否符合开闭原则是否属于 GOF 设计模式创建方式应用场景
简单工厂不符合一个工厂方法创建所有产品产品种类较少,创建逻辑简单,变化不频繁
工厂方法符合一个产品一个工厂产品种类较多,需扩展性
抽象工厂符合一组产品族使用一个工厂接口不同平台或风格的产品成组创建,创建“产品族”,产品之间有关联性

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/web/81642.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTTP 与 HTTPS 深度解析:原理、实践与大型项目应用

1. HTTP 与 HTTPS 基础概念 1.1 HTTP&#xff08;超文本传输协议&#xff09; 定义&#xff1a;应用层协议&#xff0c;基于 TCP/IP 通信&#xff0c;默认端口 80 特点&#xff1a; 无状态协议&#xff08;需 Cookie/Session 维护状态&#xff09; 明文传输&#xff08;易被…

【Excel 扩展正则的能力】工作中赋予处理单元格文本的强大正则表达提取能力

文本提取处理领域&#xff0c;正则表达式是最为强大的存在&#xff0c;工作中Excel 是常用的小型数据采集&#xff0c;处理&#xff0c;分析的工具但本身不具备正则的能力&#xff0c;让Excel拥有正则的能力无疑是如虎添翼的能力。 方案 让正则作为函数内容的一部分&#xff0c…

rabbitmq 使用过程中遇到的问题

1. 连接rabbitmq 地址写法&#xff0c;5672 是连接的端口号&#xff0c;15672是页面访问的端口号 2. elasticsearch 的访问端口是9200&#xff0c; 不是9300&#xff0c;9300 是后台通信端口号 &#xff0c;这个页面访问的端口号是一样&#xff0c; 3. rabbitmq 的5种交换接…

HTML实战:响应式个人资料页面

我将创建一个现代化的响应式个人资料页面,展示HTML在实际应用中的强大功能。这个页面将包含多个实战元素:导航栏、个人简介、技能展示、作品集和联系表单。 设计思路 使用Flexbox和Grid布局实现响应式设计 添加CSS过渡效果增强交互体验 实现深色/浅色模式切换功能 创建悬停动…

工业自动化实战:基于 VisionPro 与 C# 的机器视觉 PLC 集成方案

一、背景介绍 在智能制造领域&#xff0c;机器视觉检测与 PLC 控制的无缝集成是实现自动化生产线闭环控制的关键。本文将详细介绍如何使用 C# 开发上位机系统&#xff0c;实现 Cognex VisionPro 视觉系统与西门子 S7 PLC 的数据交互&#xff0c;打造高效、稳定的工业检测方案。…

如何处理 Python 入门难以进步的现象

Python 初学者难以进步的根本原因在于&#xff1a;缺乏项目实践、学习路径不清晰、没有掌握编程思维、忽略调试与源码阅读、缺乏系统性目标驱动。其中&#xff0c;“没有项目驱动导致学习孤岛效应”最为常见且致命。许多初学者只停留在语法知识、刷题阶段&#xff0c;无法构建可…

【后端高阶面经:缓存篇】37、高并发系统缓存性能优化:从本地到分布式的全链路设计

一、缓存性能优化的核心价值与分层架构 (一)缓存的多维价值体系 延迟优化 内存访问速度(100ns) vs 磁盘数据库(10ms+),性能提升10万倍+案例:电商详情页通过缓存将响应时间从500ms降至50ms吞吐提升 单机Redis可支撑10万QPS,分担数据库压力案例:秒杀系统通过缓存拦截9…

windows本地虚拟机上运行docker-compose案例

1、先构建镜像文件dockerfile&#xff0c;使用docker build -t redis-demo:1.0 -f dockerfile .来构建: FROM openjdk:8-jdk-alpineMAINTAINER qini<nqqq.com>VOLUME /data/upload_filesWORKDIR /usr/local/nqADD ./redis-demo.jar app.jarENV profile prod ENV timezon…

WPF布局基础

开头存一个快速排版插件 使用 XAML 格式化工具:XAML Styler - dino.c - 博客园 快捷键 在 Visual Studio 2022 中,输入类似 <Button ... /> 的自闭合 XAML 标签时,可以通过以下方式快速生成结尾的 />: 方法 1:输入 / 自动补全 输入标签名和属性: 输入 <B…

Electron 桌面程序读取dll动态库

序幕&#xff1a;被GFW狙击的第一次构建 当我在工位上输入npm install electron时&#xff0c;控制台跳出的红色警报如同数字柏林墙上的一道弹痕&#xff1a; Error: connect ETIMEDOUT 104.20.22.46:443 网络问题不用愁&#xff0c;请移步我的另外文章进行配置&#xff1a;…

javascript中运算符的优先级

优先级运算类型关联性运算符19圆括号n/a( … )18成员访问从左到右… . …Computed Member Access从左到右… [ … ]new (带参数列表)n/anew … ( … )17函数调用从左到右… ( … )new (无参数列表)从右到左new …16后置递增(运算符在后)n/a… 后置递减(运算符在后)n/a… –15逻…

Linux的交换区

Linux 交换区&#xff08;Swap&#xff09;详解 交换区&#xff08;Swap&#xff09;是 Linux 系统用于扩展内存的一种机制&#xff0c;它将部分磁盘空间虚拟成内存使用。当物理内存&#xff08;RAM&#xff09;不足时&#xff0c;系统会将不活跃的内存页移动到交换区&#xf…

阅读笔记——理解什么是LLM大语言模型

阅读笔记&#xff1a; 理解LLM deepseek创新了什么 什么是多模态 什么是token ​​ 定义​​&#xff1a;Token是LLM处理文本的最小单位&#xff0c;相当于语言的"原子"​​类比​​&#xff1a; 中文&#xff1a;1个token ≈ 1个汉字或常见词&#xff08;如"…

(自用)Java学习-5.14(注册,盐值加密,模糊查询)

一、核心功能实现 1. 用户注册功能 前端实现 用户名实时校验&#xff1a;通过AJAX异步请求检查用户名是否已存在。 function checkName() {$.ajax({url: /users/checkUserName?uname uname,success: function(resp) {if (resp.code 200) alert("用户名可用");el…

【杂谈】STM32使用快速傅里叶变换库函数后如何比较准确地找到n次谐波幅值

目录 1.简单介绍傅里叶变换的作用 2.谐波是什么 3.解决方法 1.简单介绍傅里叶变换的作用 任何复杂的波形归根结底都是由多个频率和相位不一样的正弦波组成的 通过傅里叶变换可以找到组成一个复杂的波形的所有正弦波的频率和幅度信息 2.谐波是什么 假设有一个复杂的波形&a…

芯科科技推出首批第三代无线开发平台SoC,高度集成的解决方案推动下一波物联网实现突破

SiXG301和SiXG302是芯科科技采用22纳米工艺节点推出的首批无线SoC系列产品&#xff0c;在计算能力、功效、集成度和安全性方面实现突破性进展 低功耗无线解决方案领导性创新厂商Silicon Labs&#xff08;亦称“芯科科技”&#xff0c;NASDAQ&#xff1a;SLAB&#xff09;近日宣…

写作即是生活

一个问题 “我是什么时候开始写作的呢&#xff1f;”请你先暂停一下&#xff0c;别往下读&#xff0c;先想想这个问题。 什么才是写作&#xff1f; 或许在想上个问题之后&#xff0c;你就会开始想问另外一个问题&#xff0c;什么才算是写作呢&#xff1f; 我的回答是&#x…

SpringBoot 执行Lua脚本 服务端执行 减少性能损耗 优化性能 优化连接性能

介绍 通过 Redis 执行 Lua 脚本时&#xff0c;所有的操作都在服务器端完成&#xff0c;而不是多次通过网络进行请求。这可以显著减少网络延迟&#xff0c;尤其是在需要多次与 Redis 交互的场景中。多个操作可以在 Lua 脚本中组合成一个操作&#xff0c;而不是分多次请求&#…

Nginx代理、缓存与Rewrite

目录 一、正向代理 &#xff08;一&#xff09;核心概念与应用场景 &#xff08;二&#xff09;Nginx正向代理编译安装&#xff08;以OpenEuler为例&#xff09; &#xff08;三&#xff09;验证正向代理 二、反向代理 &#xff08;一&#xff09;七层代理&#xff08;HT…

PortSwigger-02-XXE

一&#xff1a;漏洞原理 1、XXE XXE全称xml外部实体注入 XML&#xff1a;是一种用于标记电子文件使其具有结构性的标记语言&#xff0c;提供统一的方法来描述和交换独立于应用程序或者供应商的结构化数据&#xff0c;它可以用来标记数据&#xff0c;定义数据类型、是一种允许…