设计模式 | 工厂模式

工厂模式(Factory Pattern) 是创建型设计模式的核心成员,它通过将对象创建的逻辑封装起来,实现了创建与使用的解耦。本文将深入探讨工厂模式的核心思想、实现技巧以及在C++中的高效实现方式。

为什么需要工厂模式?

在软件开发中,直接使用new关键字创建对象会带来诸多问题:

  • 紧耦合:客户端代码依赖具体类实现

  • 难以扩展:添加新产品需要修改客户端代码

  • 职责混乱:对象创建逻辑分散在各处

  • 违反开闭原则:对修改开放,对扩展封闭

工厂模式通过封装对象创建过程解决了这些问题,提供了一种灵活的创建机制。当你的代码中存在以下情况时,工厂模式特别有用:

  • 无法预知需要创建的具体类型

  • 需要集中管理对象的创建逻辑

  • 系统需要支持多种类型的产品

  • 希望将实例化延迟到子类

工厂模式的两种形态

1. 简单工厂模式(静态工厂)

简单工厂模式是最基础的形式,它通过一个静态方法封装对象的创建逻辑。

#include <iostream>
#include <memory>
#include <stdexcept>// 抽象产品类:图形接口
class Shape {
public:virtual void draw() const = 0;virtual ~Shape() = default;
};// 具体产品类:圆形
class Circle : public Shape {
public:void draw() const override {std::cout << "○ 绘制圆形" << std::endl;}
};// 具体产品类:矩形
class Rectangle : public Shape {
public:void draw() const override {std::cout << "□ 绘制矩形" << std::endl;}
};// 具体产品类:三角形
class Triangle : public Shape {
public:void draw() const override {std::cout << "△ 绘制三角形" << std::endl;}
};// 简单工厂类
class ShapeFactory {
public:// 形状类型枚举enum ShapeType { CIRCLE, RECTANGLE, TRIANGLE };// 创建形状的静态方法static std::unique_ptr<Shape> createShape(ShapeType type) {switch (type) {case CIRCLE:return std::make_unique<Circle>();case RECTANGLE:return std::make_unique<Rectangle>();case TRIANGLE:return std::make_unique<Triangle>();default:throw std::invalid_argument("错误:不支持的形状类型");}}
};// 创建具体实列
int main() {// 创建圆形auto circle = ShapeFactory::createShape(ShapeFactory::CIRCLE);circle->draw();// 创建矩形auto rect = ShapeFactory::createShape(ShapeFactory::RECTANGLE);rect->draw();// 创建三角形auto triangle = ShapeFactory::createShape(ShapeFactory::TRIANGLE);triangle->draw();return 0;
}

优点

  • 实现简单,易于理解

  • 集中管理对象的创建逻辑

  • 客户端与具体产品类解耦

缺点

  • 违反开闭原则(添加新产品需修改工厂类)

  • 工厂类职责过重(所有产品都在一个工厂中创建)

  • 不支持运行时动态扩展

2. 工厂方法模式

工厂方法模式将对象创建延迟到子类,解决了简单工厂的开闭原则问题。

#include <iostream>
#include <memory>
#include <vector>// 抽象产品:日志记录器
class Logger {
public:virtual void log(const std::string& message) = 0;virtual ~Logger() = default;
};// 具体产品:文件日志
class FileLogger : public Logger {
public:void log(const std::string& message) override {std::cout << "[文件日志] " << message << std::endl;}
};// 具体产品:控制台日志
class ConsoleLogger : public Logger {
public:void log(const std::string& message) override {std::cout << "[控制台日志] " << message << std::endl;}
};// 具体产品:网络日志
class NetworkLogger : public Logger {
public:void log(const std::string& message) override {std::cout << "[网络日志] " << message << std::endl;}
};// 抽象创建者
class LoggerCreator {
public:virtual std::unique_ptr<Logger> createLogger() = 0;void logMessage(const std::string& message) {auto logger = createLogger();logger->log(message);}virtual ~LoggerCreator() = default;
};// 具体创建者:文件日志工厂
class FileLoggerCreator : public LoggerCreator {
public:std::unique_ptr<Logger> createLogger() override {return std::make_unique<FileLogger>();}
};// 具体创建者:控制台日志工厂
class ConsoleLoggerCreator : public LoggerCreator {
public:std::unique_ptr<Logger> createLogger() override {return std::make_unique<ConsoleLogger>();}
};// 具体创建者:网络日志工厂
class NetworkLoggerCreator : public LoggerCreator {
public:std::unique_ptr<Logger> createLogger() override {return std::make_unique<NetworkLogger>();}
};// 创建实例
int main() {std::vector<std::unique_ptr<LoggerCreator>> creators;creators.push_back(std::make_unique<FileLoggerCreator>());creators.push_back(std::make_unique<ConsoleLoggerCreator>());creators.push_back(std::make_unique<NetworkLoggerCreator>());for (auto& creator : creators) {creator->logMessage("应用启动完成");}return 0;
}

核心思想

  • 定义创建对象的接口,但让子类决定实例化哪个类

  • 工厂方法使一个类的实例化延迟到其子类

  • 符合"开闭原则" - 对扩展开放,对修改关闭

工厂方法模式的高级应用

1. 参数化工厂方法

class UniversalCreator : public LoggerCreator {
public:enum LoggerType { FILE, CONSOLE, NETWORK };UniversalCreator(LoggerType type) : type_(type) {}std::unique_ptr<Logger> createLogger() override {switch (type_) {case FILE: return std::make_unique<FileLogger>();case CONSOLE: return std::make_unique<ConsoleLogger>();case NETWORK: return std::make_unique<NetworkLogger>();default: throw std::invalid_argument("无效的日志类型");}}private:LoggerType type_;
};// 使用示例
int main() {UniversalCreator fileCreator(UniversalCreator::FILE);fileCreator.logMessage("保存到文件");UniversalCreator consoleCreator(UniversalCreator::CONSOLE);consoleCreator.logMessage("输出到控制台");return 0;
}

2. 工厂方法 + 单例模式

class Database {
public:virtual void connect() = 0;virtual ~Database() = default;
};class MySQL : public Database {
public:void connect() override {std::cout << "连接到MySQL数据库" << std::endl;}static MySQL& getInstance() {static MySQL instance;return instance;}private:MySQL() = default;
};class PostgreSQL : public Database {
public:void connect() override {std::cout << "连接到PostgreSQL数据库" << std::endl;}static PostgreSQL& getInstance() {static PostgreSQL instance;return instance;}private:PostgreSQL() = default;
};class DatabaseFactory {
public:virtual Database& create() = 0;virtual ~DatabaseFactory() = default;
};class MySQLFactory : public DatabaseFactory {
public:Database& create() override {return MySQL::getInstance();}
};class PostgreSQLFactory : public DatabaseFactory {
public:Database& create() override {return PostgreSQL::getInstance();}
};// 使用示例
int main() {MySQLFactory mysqlFactory;auto& mysql = mysqlFactory.create();mysql.connect();PostgreSQLFactory pgFactory;auto& pg = pgFactory.create();pg.connect();return 0;
}

工厂模式的优缺点分析

优点

  • 解耦创建者和具体产品

  • 符合开闭原则,易于扩展

  • 单一职责原则(创建逻辑集中)

  • 便于代码维护和测试

  • 支持依赖倒置原则

缺点

  • 引入额外类,增加系统复杂性

  • 需要设计良好的继承体系

  • 客户端可能需要理解工厂结构

  • 简单场景下可能显得过度设计

工厂模式的典型应用场景

  1. 框架设计:框架需要为应用提供扩展点

    class Plugin {
    public:virtual void execute() = 0;virtual ~Plugin() = default;
    };class PluginFactory {
    public:virtual std::unique_ptr<Plugin> createPlugin() = 0;
    };
  2. 跨平台开发:为不同平台创建适配对象

    class GUIButton {
    public:virtual void render() = 0;
    };class WindowsButton : public GUIButton { /*...*/ };
    class MacButton : public GUIButton { /*...*/ };class GUIFactory {
    public:virtual std::unique_ptr<GUIButton> createButton() = 0;
    };
  3. 对象池管理:管理可重用对象的创建

    class Connection {
    public:virtual void open() = 0;
    };class ConnectionPool {
    public:virtual std::unique_ptr<Connection> createConnection() = 0;virtual void returnConnection(std::unique_ptr<Connection>) = 0;
    };
  4. 依赖注入:通过工厂注入依赖对象

    class Service {
    public:virtual void performTask() = 0;
    };class Client {
    public:Client(std::unique_ptr<ServiceFactory> factory): factory_(std::move(factory)) {}void execute() {auto service = factory_->createService();service->performTask();}private:std::unique_ptr<ServiceFactory> factory_;
    };

工厂模式的最佳实践

  1. 优先使用工厂方法:除非系统非常简单,否则优先选择工厂方法模式

  2. 结合智能指针:使用std::unique_ptrstd::shared_ptr管理对象生命周期

  3. 使用模板减少重复代码

    template <typename T>
    class StandardCreator : public LoggerCreator {
    public:std::unique_ptr<Logger> createLogger() override {return std::make_unique<T>();}
    };// 使用
    StandardCreator<FileLogger> fileCreator;
  4. 工厂方法命名规范

  • createXXX()

  • makeXXX()

  • newXXX()

  • getInstance() (单例场景)

工厂模式 vs 简单工厂

特性简单工厂模式工厂方法模式
开闭原则违反(修改工厂类)支持(扩展子类)
复杂度简单中等
扩展性有限优秀
类数量较少较多(每个产品对应工厂)
适用场景产品类型少且固定产品类型多或可能扩展

总结

工厂模式是C++开发中强大的对象创建工具,通过封装对象的创建过程,它实现了:

  • 解耦:客户端代码与具体类实现分离

  • 扩展性:轻松添加新产品而不影响现有代码

  • 可维护性:集中管理创建逻辑

  • 灵活性:支持运行时决策和配置

在实际开发中,应当根据具体需求选择合适的工厂模式变体:

  • 对于简单场景,简单工厂足够高效

  • 对于需要高度扩展的系统,工厂方法是最佳选择

  • 避免过早优化,但为未来扩展留有余地

"设计模式不是银弹,而是工具箱中的工具。工厂模式是其中最常用且强大的工具之一。" - 设计模式实践者

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

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

相关文章

数字孪生技术驱动UI前端变革:从静态展示到动态交互的飞跃

hello宝子们...我们是艾斯视觉擅长ui设计、前端开发、数字孪生、大数据、三维建模、三维动画10年经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩! 在数字化转型的深水区&#xff0c;数字孪生技术正以破竹之势重构 UI 前端的技术逻辑与设计理念…

Django实战:自定义中间件实现全链路操作日志记录

文章目录 一、中间件介绍激活中间件生命周期 二、自定义中间件中间件钩子函数基于类的中间件 三、实战案例操作日志功能参考资料 一、中间件 介绍 在 Django 中&#xff0c;中间件&#xff08;Middleware&#xff09;是一组轻量级、底层的插件系统&#xff0c;用于全局地改变…

Java编程之迭代器模式(Iterator Pattern)

引言&#xff1a; 走进图书馆&#xff0c;你站在一排书架前&#xff0c;想要浏览书籍。你会一格格地从左到右翻阅书籍&#xff0c;而不是去研究书架是什么。 一本书一本书地翻&#xff0c;才知道书架上藏了什么书&#xff0c;研究书架的构造是不知道书籍的内容的。 这种“逐本…

ARM64 linux系统的一般执行过程

1、正在运行的用户进程X 2、发生异常&#xff08;包括系统调用等&#xff09;&#xff0c;CPU完成的工作&#xff1a;把当前程序指针寄存器PC放入ELR_EL1寄存器&#xff0c;把PSTATE放入SPSR_EL1寄存器&#xff0c;把异常产生的原因放在ESR_EL1寄存器&#xff0c;将异常向量表…

Vue3+ element 实现导入导出

一、导入功能相关代码分析 相关变量定义 importVisible&#xff1a;这是一个ref类型的响应式变量&#xff0c;用于控制导入对话框的显示与隐藏&#xff0c;初始值为false。当用户点击 “导入” 按钮时&#xff0c;会尝试将其值设为true来显示导入对话框&#xff0c;若出现异常则…

Git安装(纯小白版)

一、Git安装 1. 简介 Git是一款免费开源的分布式版本控制系统&#xff0c;常用于软件开发。它能记录文件在不同时间的改动&#xff0c;让用户在需要时查看、恢复旧版本。支持多人协作开发&#xff0c;多人可同时修改项目文件&#xff0c;Git会处理好冲突。开发者能在本地创建…

cocos2 本地根据文本内容生成二维码

cocos2 本地根据文本内容生成二维码 之前做了一个功能&#xff0c;就是cocos2小游戏&#xff0c;结算页面需要有一个二维码&#xff0c;二维码内容是一个网址&#xff0c;这个网址需要根据用户游玩分数确定访问哪个网址&#xff0c;但是这个小游戏是单机小游戏&#xff0c;不连…

87.xilinx FPGA读取器件id方法

dout数据高位先出msb module chip_id_reader(input clk,input reset,output [56:0] dna_value,output dna_valid );reg [6:0] bit_count;reg [56:0] dna_shift_reg;reg dna_read;reg dna_shift;wire dna_out;// 实例化DNA_PORT原语DNA_PORT #(.SIM_DNA_VALUE(57h123456789ABCD…

AcWing--数据结构(二)

Trie 树 用来高效的快速存储和查找字符串集合的数据结构 如存储&#xff1a;abcdef,abdef,aced,... 从根节点开始存储&#xff0c;从前往后存储&#xff0c;看是否有a&#xff0c;没有就创建&#xff0c;依次存储。 一般在最后一个字符打个标记&#xff0c;意思就是当前字符…

论基于架构的软件设计方法(ABSD)及应用

2025年3月22日作 题目 基于架构的软件设计&#xff08;Architecture-Based Software Design, ABSD&#xff09;方法以构成软件架构的商业、质量和功能需求等要素来驱动整个软件开发过程。ABSD是一个自顶向下&#xff0c;递归细化的软件开发方法&#xff0c;它以软件系统功能的…

【Docker基础】Docker容器管理:docker exec详解

目录 1 docker exec命令概述 1.1 命令定位与作用 1.2 与相似命令对比 2 基本语法与参数解析 2.1 完整命令语法 2.2 核心参数详解 2.2.1 -i, --interactive 2.2.2 -t, --tty 2.2.3 -d, --detach 2.2.4 -e, --env 2.2.5 -u, --user 2.2.6 -w, --workdir 3 典型使用场…

CSS3实现同心圆效果

效果图&#xff1a; 文本左侧显示一个 外圆&#xff08;30px&#xff0c;半透明&#xff09; 和 内圆&#xff08;12px&#xff0c;实色&#xff09; 的同心圆&#xff1a; <!DOCTYPE html> <html> <head><style>.text-with-circles {position: rela…

Spring Boot项目开发实战销售管理系统——系统设计!

Spring Boot项目开发实战——销售管理系统 在前面的章节中我们详细介绍了Spring Boot各个功能的使用&#xff0c;本章将新建一个销售管理系统项目&#xff0c;演示项目从需求分析到功能分解&#xff0c;再到各个功能的实现过程&#xff0c;最后再使用Docker部署上线的完整过程…

RK3588开发笔记-Hailo AI模块调试

目录 前言 一、RK3588 与 Hailo AI 模块简介 RK3588 Hailo AI 模块 二、原理图连接 三、内核配置 四、Hailo驱动编译 五、Hailo模块验证 总结 前言 在边缘计算和人工智能应用不断发展的今天,将高性能的 AI 模块与功能强大的开发板相结合,能为各种创新应用提供坚实的基…

【Pytorch】语言模型上的动态量化

目录 ■导言 ①定义模型 ②加载文本数据 ③加载预训练模型 ④测试动态量化 ■结论 ■导言 量化涉及将模型的权重和激活从float转换为int&#xff0c;这可以导致更小的模型大小和更快的推理&#xff0c;并且只对准确性造成很小的影响。 本文将把最简单的量化形式-动态量…

【有啥问啥】大模型效率部署之Prefill-Decode分离

大模型效率部署之Prefill-Decode分离 Prefill 与 Decode 阶段定义与流程 LLM 推理分为两个阶段&#xff1a;预填充&#xff08;Prefill&#xff09;和解码&#xff08;Decode&#xff09;。在 Prefill 阶段&#xff0c;模型将完整地处理用户输入的所有提示词&#xff08;prom…

QT Creator构建失败:-1: error: Unknown module(s) in QT: serialport

Qt Creator和Qt SDK版本&#xff1a; Product: Qt Creator 17.0.0 Based on: Qt 6.9.1 (MSVC 2022, x86_64) Built on: Jun 17 2025 16:32:24 From revision: 4983f08c47 问题&#xff1a; 在使用串口的时候&#xff0c;在pro 文件中添加了 QT serialport&#xff…

基于PostgreSQL的百度或高德等POI多层级分类的数据库设计

目录 前言 一、百度 VS 高德 POI分类 1、高德POI分类 2、百度POI分类 3、分类对比与区别 二、POI分类表设计 1、物理表结构 2、数据存储 3、数据查询 三、总结 前言 在当今数字化快速发展的时代&#xff0c;地理信息数据的重要性日益凸显&#xff0c;而POI&#xff08…

AutoVLA:端到端自动驾驶中具有自适应推理和强化微调功能的视觉-语言-动作模型

26年6月来自UCLA的论文“AutoVLA: A Vision-Language-Action Model for End-to-End Autonomous Driving with Adaptive Reasoning and Reinforcement Fine-Tuning”。 视觉-语言-动作 (VLA) 模型的最新进展通过利用世界知识和推理能力为端到端自动驾驶带来了希望。然而&#x…

知攻善防靶机 Windows 近源OS

知攻善防靶机 [hvv训练]应急响应靶机训练-近源渗透OS-1 前景需要&#xff1a;小王从某安全大厂被优化掉后&#xff0c;来到了某私立小学当起了计算机老师。某一天上课的时候&#xff0c;发现鼠标在自己动弹&#xff0c;又发现除了某台电脑&#xff0c;其他电脑连不上网络。感觉…