設計模式 之 工廠模式(簡單工廠模式、工廠方法模式、抽象工廠模式)(C++)

文章目錄

  • C++ 工廠模式
    • 引言
    • 一、簡單工廠模式
      • 概念
      • 實現步驟
      • 示例代碼
      • 優缺點
    • 二、工廠方法模式
      • 概念
      • 實現步驟
      • 示例代碼
      • 優缺點
    • 三、抽象工廠模式
      • 概念
      • 實現步驟
      • 示例代碼
      • 優缺點

C++ 工廠模式

引言

在 C++ 編程中,對象的創建是一個常見且基礎的操作。然而,當項目規模逐漸增大,對象的創建邏輯變得復雜時,直接在代碼中使用 new 關鍵字創建對象會帶來諸多問題,比如代碼的可維護性變差、難以擴展等。工廠模式應運而生,它為對象的創建提供了一種更加靈活、可擴展的解決方案。本文將詳細介紹 C++ 中的工廠模式,包括簡單工廠模式、工廠方法模式和抽象工廠模式,并通過具體的例子幫助大家理解。

一、簡單工廠模式

概念

簡單工廠模式是工廠模式的基礎版本,它定義了一個工廠類,該類可以根據傳入的參數決定創建并返回哪種產品類的實例。簡單來說,就是把對象的創建邏輯封裝在一個工廠類中。

實現步驟

  1. 定義產品基類:創建一個抽象的產品基類,所有具體產品類都要繼承這個基類。
  2. 創建具體產品類:實現產品基類的接口,創建具體的產品類。
  3. 創建工廠類:在工廠類中定義一個創建產品的方法,根據傳入的參數決定創建哪種具體產品。

示例代碼

#include<iostream>
#include<memory>// 定義水果抽象基類,包含純虛函數 name
class Fruit{public:// 純虛函數,用于輸出水果名稱,派生類需實現virtual void name()=0;
};// 蘋果類,繼承自 Fruit 類
class Apple:public Fruit{public:// 重寫基類的 name 函數,輸出蘋果名稱void name() override{std::cout<<"Apple"<<std::endl;}
};// 香蕉類,繼承自 Fruit 類
class Banana:public Fruit{public:// 重寫基類的 name 函數,輸出香蕉名稱void name() override{std::cout<<"Banana"<<std::endl;}
};// 工廠類,用于創建不同類型的水果對象
class Factory{public:// 靜態方法,根據傳入的水果名稱創建對應的水果對象static std::unique_ptr<Fruit> createFruit(std::string fruit_name){if(fruit_name=="apple"){// 創建蘋果對象并返回其 unique_ptrreturn std::unique_ptr<Fruit>(new Apple());}else if(fruit_name=="banana"){// 創建香蕉對象并返回其 unique_ptrreturn std::unique_ptr<Fruit>(new Banana());}else{// 若名稱不匹配,返回空指針return nullptr;}}
};int main()
{// 使用工廠類創建蘋果對象std::unique_ptr<Fruit> fruit = Factory::createFruit("apple");// 調用蘋果對象的 name 函數輸出名稱fruit->name();  // 使用工廠類創建香蕉對象fruit = Factory::createFruit("banana");// 調用香蕉對象的 name 函數輸出名稱fruit->name();// 再次使用工廠類創建蘋果對象fruit = Factory::createFruit("apple");return 0;
}

優缺點

  • 優點:實現簡單,將對象的創建和使用分離,提高了代碼的可維護性。
  • 缺點:工廠類職責過重,違反了開閉原則(對擴展開放,對修改關閉)。如果需要新增產品,就需要修改工廠類的代碼。

二、工廠方法模式

概念

工廠方法模式是在簡單工廠模式的基礎上進行了改進,它將創建對象的具體邏輯延遲到子類中實現。定義一個創建對象的抽象方法,讓子類決定實例化哪個具體產品類。

實現步驟

  1. 定義產品基類:同簡單工廠模式。
  2. 創建具體產品類:同簡單工廠模式。
  3. 定義抽象工廠類:定義一個抽象的工廠類,其中包含一個抽象的創建產品的方法。
  4. 創建具體工廠類:繼承抽象工廠類,實現創建產品的方法,決定創建哪種具體產品。

示例代碼

#include<iostream>
#include<memory>// 定義抽象基類 Fruit,包含純虛函數 name
// 任何繼承自該類的具體水果類都必須實現 name 函數
class Fruit {
public:// 純虛函數,用于輸出水果名稱virtual void name() = 0;
};// 定義 Apple 類,繼承自 Fruit 類
class Apple : public Fruit {
public:// 重寫基類的純虛函數 name,輸出蘋果名稱void name() override {std::cout << "Apple" << std::endl;}
};// 定義 Banana 類,繼承自 Fruit 類
class Banana : public Fruit {
public:// 重寫基類的純虛函數 name,輸出香蕉名稱void name() override {std::cout << "Banana" << std::endl;}
};// 定義抽象工廠類 Factory,包含純虛函數 create
// 具體的工廠類需要實現該函數來創建水果對象
class Factory {
public:// 純虛函數,用于創建水果對象virtual std::shared_ptr<Fruit> create() = 0;
};// 定義 AppleFactory 類,繼承自 Factory 類
class AppleFactory : public Factory {
public:// 重寫基類的純虛函數 create,創建蘋果對象std::shared_ptr<Fruit> create() override {return std::make_shared<Apple>();}
};// 定義 BananaFactory 類,繼承自 Factory 類
class BananaFactory : public Factory {
public:// 重寫基類的純虛函數 create,創建香蕉對象std::shared_ptr<Fruit> create() override {return std::make_shared<Banana>();}
};int main() {// 創建一個指向 AppleFactory 的智能指針std::shared_ptr<Factory> fruit_factory(new AppleFactory());// 調用工廠的 create 方法創建蘋果對象std::shared_ptr<Fruit> fruit = fruit_factory->create();// 調用水果對象的 name 方法輸出名稱fruit->name();// 重置工廠指針,指向 BananaFactoryfruit_factory.reset(new BananaFactory());// 調用新工廠的 create 方法創建香蕉對象fruit = fruit_factory->create();// 調用水果對象的 name 方法輸出名稱fruit->name();return 0;
}

優缺點

  • 優點:符合開閉原則,當需要新增產品時,只需要新增具體產品類和對應的具體工廠類,不需要修改現有代碼。
  • 缺點:類的數量會增多,增加了系統的復雜度。

三、抽象工廠模式

概念

抽象工廠模式:工廠方法模式通過引入工廠等級結構,解決了簡單工廠模式中工廠類職責太重的問題。但由于工廠方法模式中的每個工廠只生產一類產品,可能會導致系統中存在大量的工廠類,勢必會增加系統的開銷。此時,我們可以考慮將一些相關的產品組成一個產品族(位于不同產品等級結構中功能相關聯的產品組成的家族),由同一個工廠來統一生產,這就是抽象工廠模式的基本思想。

實現步驟

  1. 定義產品族的抽象基類:為每個產品族定義一個抽象基類。
  2. 創建具體產品類:實現每個產品族的具體產品類。
  3. 定義抽象工廠類:定義一個抽象的工廠類,其中包含多個創建不同產品的抽象方法。
  4. 創建具體工廠類:繼承抽象工廠類,實現創建不同產品的方法,決定創建哪些具體產品。

示例代碼

#include<iostream>
#include<memory>// 水果抽象基類,定義了輸出水果名稱的純虛函數
class Fruit {
public:virtual void name() = 0;
};// 蘋果類,繼承自 Fruit 類,實現了輸出蘋果名稱的方法
class Apple : public Fruit {
public:void name() override {std::cout << "Apple" << std::endl;}
};// 香蕉類,繼承自 Fruit 類,實現了輸出香蕉名稱的方法
class Banana : public Fruit {
public:void name() override {std::cout << "Banana" << std::endl;}
};// 動物抽象基類,定義了輸出動物名稱的純虛函數
class Animal {
public:virtual void name() = 0;
};// 羊類,繼承自 Animal 類,實現輸出名稱方法
class Lamb : public Animal {
public:void name() override {std::cout << "Lamb" << std::endl;}
};// 狗類,繼承自 Animal 類,實現了輸出狗名稱的方法
class Dog : public Animal {
public:void name() override {std::cout << "Dog" << std::endl;}
};// 抽象工廠類,定義了獲取水果和動物對象的純虛函數
class Factory {
public:virtual std::shared_ptr<Fruit> getFruit(const std::string& name) = 0;virtual std::shared_ptr<Animal> getAnimal(const std::string& name) = 0;
};// 水果工廠類,繼承自 Factory 類,實現了獲取水果對象的方法,獲取動物對象返回空指針
class FruitFactory : public Factory {
public:virtual std::shared_ptr<Fruit> getFruit(const std::string& name);virtual std::shared_ptr<Animal> getAnimal(const std::string& name);
};// 動物工廠類,繼承自 Factory 類,實現了獲取動物對象的方法,獲取水果對象返回空指針
class AnimalFactory : public Factory {
public:virtual std::shared_ptr<Fruit> getFruit(const std::string& name);virtual std::shared_ptr<Animal> getAnimal(const std::string& name);
};// 工廠管理類,提供靜態方法根據名稱創建對應的工廠對象
class FactoryManager {
public:static std::shared_ptr<Factory> creaete(const std::string& name);
};int main() {// 通過工廠管理類創建水果工廠對象std::shared_ptr<Factory> fruit_factory = FactoryManager::creaete("fruit");// 從水果工廠獲取蘋果對象并輸出名稱std::shared_ptr<Fruit> fruit = fruit_factory->getFruit("apple");fruit->name();// 從水果工廠獲取香蕉對象并輸出名稱fruit = fruit_factory->getFruit("banana");fruit->name();return 0;
}

優缺點

  • 優點:將一系列相關的產品對象的創建封裝在一起,保證了產品之間的一致性,同時也符合開閉原則。
  • 缺點:實現復雜,當產品族需要增加新的產品時,需要修改抽象工廠類和所有具體工廠類的代碼。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/71483.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/71483.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/71483.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

DAY12 Tensorflow 六步法搭建神經網絡

六步法&#xff1a; 一.import 導入各種庫&#xff0c;比如&#xff1a; import tensorflow as tf from tensorflow.keras.layers import Dense, Flatten from tensorflow.keras import Model import numpy as np import pandas as pd # 可能還會根據需求導入其他庫&…

Zookeeper分布式鎖實現

zookeeper最初設計的初衷就是為了保證分布式系統的一致性。本文將講解如何利用zookeeper的臨時順序結點&#xff0c;實現分布式鎖。 目錄 1. 理論分析 1.1 結點類型 1.2 監聽器 1.3 實現原理 2. 手寫實現簡易zookeeper分布式鎖 1.1 依賴 1.2 常量定義 1.3 實現zookeeper分布式…

Git是什么

簡單介紹&#xff1a; Git是一個分布式版本控制系統&#xff0c;用于跟蹤文件的更改&#xff0c;特別是在多人協作開發的環境中。 Key: 分布式 版本控制 系統 最常用于軟件開發&#xff0c;但也可以用于管理任何類型的文件和文件夾。 Git幫助團隊跟蹤和管理文件的歷史版本&a…

Pycharm 2024在解釋器提供的python控制臺中運行py文件

2024版的界面發生了變化, run with python console搬到了這里:

【分布式理論12】事務協調者高可用:分布式選舉算法

文章目錄 一、分布式系統中事務協調的問題二、分布式選舉算法1. Bully算法2. Raft算法3. ZAB算法 三、小結與比較 一、分布式系統中事務協調的問題 在分布式系統中&#xff0c;常常有多個節點&#xff08;應用&#xff09;共同處理不同的事務和資源。前文 【分布式理論9】分布式…

免費deepseek的API獲取教程及將API接入word或WPS中

免費deepseek的API獲取教程: 1 https://cloud.siliconflow.cn/中注冊時填寫邀請碼&#xff1a;GAejkK6X即可獲取2000 萬 Tokens; 2 按照圖中步驟進行操作 將API接入word或WPS中 1 打開一個word&#xff0c;文件-選項-自定義功能區-勾選開發工具-左側的信任中心-信任中心設置…

【SFRA】筆記

GK_SFRA_INJECT(x) SFRA小信號注入函數,向控制環路注入一個小信號。如下圖所示,當前程序,小信號注入是在固定占空比的基礎疊加小信號,得到新的占空比,使用該占空比控制環路。 1.2 GK_SFRA_COLLECT(x, y) SFRA數據收集函數,將小信號注入環路后,該函數收集環路的數據,以…

論文筆記-WSDM2024-LLMRec

論文筆記-WSDM2024-LLMRec: Large Language Models with Graph Augmentation for Recommendation LLMRec: 基于圖增強的大模型推薦摘要1.引言2.前言2.1使用圖嵌入推薦2.2使用輔助信息推薦2.3使用數據增強推薦 3.方法3.1LLM作為隱式反饋增強器3.2基于LLM的輔助信息增強3.2.1用戶…

Ubuntu 系統 cuda12.2 安裝 MMDetection3D

DataBall 助力快速掌握數據集的信息和使用方式&#xff0c;會員享有 百種數據集&#xff0c;持續增加中。 需要更多數據資源和技術解決方案&#xff0c;知識星球&#xff1a; “DataBall - X 數據球(free)” 貴在堅持&#xff01; ---------------------------------------…

Tomcat的升級

Tomcat 是一個開源的 Java Servlet 容器&#xff0c;用于部署 Java Servlet 和 JavaServer Pages&#xff08;JSP&#xff09;。隨著新版本的發布&#xff0c;Tomcat 通常會帶來性能改進、安全增強、新特性和對最新 Java 版本的更好支持。升級 Tomcat 服務器通常涉及到以下幾個…

Python常見面試題的詳解10

1. 哪些操作會導致 Python 內存溢出&#xff0c;怎么處理&#xff1f; 要點 1. 創建超大列表或字典&#xff1a;當我們一次性創建規模極為龐大的列表或字典時&#xff0c;會瞬間占用大量的內存資源。例如&#xff0c;以下代碼試圖創建一個包含 10 億個元素的列表&#xff0c;在…

多個用戶如何共用一根網線傳輸數據

前置知識 一、電信號 網線&#xff08;如以太網線&#xff09;中傳輸的信號主要是 電信號&#xff0c;它攜帶著數字信息。這些信號用于在計算機和其他網絡設備之間傳輸數據。下面是一些關于網線傳輸信號的詳細信息&#xff1a; 1. 電信號傳輸 在以太網中&#xff0c;數據是…

華為昇騰 910B 部署 DeepSeek-R1 蒸餾系列模型詳細指南

本文記錄 在 華為昇騰 910B(65GB) * 8 上 部署 DeepSeekR1 蒸餾系列模型&#xff08;14B、32B&#xff09;全過程與測試結果。 NPU&#xff1a;910B3 (65GB) * 8 &#xff08;910B 有三個版本 910B1、2、3&#xff09; 模型&#xff1a;DeepSeek-R1-Distill-Qwen-14B、DeepSeek…

【前端】Vue組件庫之Element: 一個現代化的 UI 組件庫

文章目錄 前言一、官網1、官網主頁2、設計原則3、導航4、組件 二、核心功能&#xff1a;開箱即用的組件生態1、豐富的組件體系2、特色功能亮點 三、快速上手&#xff1a;三步開啟組件化開發1、安裝&#xff08;使用Vue 3&#xff09;2、全局引入3、按需導入&#xff08;推薦&am…

關于uniApp的面試題及其答案解析

我的血液里流淌著戰意&#xff01;力量與智慧指引著我&#xff01; 文章目錄 1. 什么是uniApp&#xff1f;2. uniApp與原生小程序開發有什么區別&#xff1f;3. 如何使用uniApp實現條件編譯&#xff1f;4. uniApp支持哪些平臺&#xff0c;各有什么特點&#xff1f;5. 在uniApp中…

Ubuntu 下 nginx-1.24.0 源碼分析 - ngx_pool_t 類型

ngx_pool_t 定義在 src/core/ngx_core.h typedef struct ngx_pool_s ngx_pool_t; ngx_pool_s 定義在 src/core/ngx_palloc.h struct ngx_pool_s {ngx_pool_data_t d;size_t max;ngx_pool_t *current;ngx_chain_t *chain;ng…

力扣 最長遞增子序列

動態規劃&#xff0c;二分查找。 題目 由題&#xff0c;從數組中找一個最長子序列&#xff0c;不難想到&#xff0c;當這個子序列遞增子序列的數越接近時是越容易拉長的。從dp上看&#xff0c;當遍歷到這個數&#xff0c;會從前面的dp選一個最大的數加上當前數&#xff0c;注意…

Linux | 進程控制(進程終止與進程等待)

文章目錄 Linux | 進程控制 — 進程終止 & 進程等待1、進程終止進程常見退出方法1.1退出碼基本概念獲取退出碼的方式常見退出碼約定使用場景 1.2 strerror函數 & errno宏1.3 _exit函數1.4_exit和exit的區別1.4.1 所屬頭文件與函數原型1.4.2 執行過程差異**結合現象分析…

Android - Handler使用post之后,Runnable沒有執行

問題&#xff1a;子線程創建的Handler。如果 post 之后&#xff0c;在Handler.removeCallbacks(run)移除了&#xff0c;下次再使用Handler.postDelayed(Runnable)接口或者使用post時&#xff0c;Runnable是沒有執行。導致沒有收到消息。 解決辦法&#xff1a;只有主線程創建的…

魚皮面試鴨30天后端面試營

day1 1. MySQL的索引類型有哪些? MySQL里的索引就像是書的目錄&#xff0c;能幫數據庫快速找到你要的數據。以下是各種索引類型的通俗解釋&#xff1a; 按數據結構分 B樹索引&#xff1a;最常用的一種&#xff0c;數據像在一棵樹上分層存放&#xff0c;能快速定位范圍數據…