設計模式 | 工廠模式

工廠模式(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
英文地址,請注明出處:http://en.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;其他電腦連不上網絡。感覺…