從C++編程入手設計模式2——工廠模式

從C++編程入手設計模式

工廠模式

? 我們馬上就要迎來我們的第二個創建型設計模式:工廠方法模式(Factory Method Pattern)。換而言之,我們希望使用一個這樣的接口,使用其他手段而不是直接創建的方式(說的有點奇怪,大致意思是——不是直接new,而是使用父子對象機制,給定一個判斷條件讓我們的工廠類選擇創建具體的子類)

? 這是因為在軟件開發中,直接在代碼中使用 new 關鍵字創建對象會導致代碼與具體類緊密耦合,降低了系統的靈活性和可擴展性。工廠方法模式通過引入工廠接口和具體工廠類,將對象的創建過程封裝起來,使得客戶端代碼與具體產品類解耦,從而提高了系統的可維護性和可擴展性。

? 一個完整的工廠模式中存在四個基本的類。

  1. 抽象產品(Product):定義產品的接口,是所有具體產品類的父類。
  2. 具體產品(ConcreteProduct):實現了抽象產品接口的具體類,表示被創建的對象。
  3. 抽象工廠(Creator):聲明工廠方法 factoryMethod(),返回抽象產品類型的對象。
  4. 具體工廠(ConcreteCreator):實現抽象工廠中的工廠方法,返回具體產品的實例。

? 很顯然,抽象的產品和類是一個接口,我們所有的產品都需要滿足這個接口,或者說,是屬于這個產品類的對象,需要被對應的具體的工廠所創建。當然,對于小項目,筆者一般喜歡合并抽象工廠和具體工廠為工廠,這樣的話直接對這工廠類發起對象創建請求即可。

C++實現的一些要點

  • 使用抽象類和虛函數:通過定義抽象產品類和抽象工廠類,利用虛函數實現多態性,使得客戶端代碼可以通過基類指針或引用操作具體產品對象。
  • 使用智能指針管理對象生命周期:為了避免內存泄漏,建議使用 std::unique_ptrstd::shared_ptr 管理動態分配的對象。
  • 將對象創建邏輯封裝在工廠類中:將具體產品類的實例化過程封裝在具體工廠類中,客戶端代碼只需調用工廠方法獲取產品對象,而無需關心具體的創建細節。

? 下面是一個非常經典的例子,但是不夠好,體現不出來為什么工廠模式存在,但是繪景代碼是如下的:

#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 a Circle" << std::endl;}
};class Square : public Shape {
public:void draw() override {std::cout << "Drawing a Square" << std::endl;}
};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>();}
};class SquareFactory : public ShapeFactory {
public:std::unique_ptr<Shape> createShape() override {return std::make_unique<Square>();}
};int main() {std::unique_ptr<ShapeFactory> circleFactory = std::make_unique<CircleFactory>();std::unique_ptr<Shape> circle = circleFactory->createShape(); // 是一個shapecircle->draw(); // 但是是circle,所以調用的就是circle的方法std::unique_ptr<ShapeFactory> squareFactory = std::make_unique<SquareFactory>();std::unique_ptr<Shape> square = squareFactory->createShape();square->draw();return 0;
}

一些你需要注意的事情

  • 避免過度使用:在對象創建過程簡單且不會發生變化的情況下,使用工廠方法模式可能會增加系統的復雜性,導致代碼冗余。(換而言之,不要到處用這個東西,除非真需要了(大量相似對象的創建))
  • 合理組織類結構:隨著產品種類和工廠類的增加,類的數量也會增加,需要合理組織類結構,避免類爆炸。
  • 結合其他設計模式使用:工廠方法模式可以與其他設計模式(如單例模式、抽象工廠模式)結合使用,以滿足更復雜的系統需求。

例子:快餐連鎖店的漢堡制作系統

背景:

您正在為一家快餐連鎖店開發一個漢堡制作系統。不同的快餐品牌(如麥當勞和漢堡王)有各自的漢堡制作方式,包括使用的面包類型、配料和包裝方式。

任務:

  1. 定義一個抽象基類 Burger,包含純虛函數 grill()prepare()wrap(),以及成員變量如 namebunTypecondiments
  2. 實現具體的漢堡類,如 McDonaldsCheeseBurgerBurgerKingCheeseBurger,分別繼承自 Burger,并實現上述方法,輸出相應的制作步驟。
  3. 創建一個抽象工廠類 BurgerJoint,包含純虛函數 createBurger(const std::string& type),用于創建不同類型的漢堡。
  4. 實現具體的工廠類,如 McDonaldsBurgerKing,繼承自 BurgerJoint,根據傳入的類型創建相應的漢堡實例。
  5. 在主函數中,模擬客戶在不同快餐店點餐的過程,使用工廠類創建漢堡對象,并調用其制作方法。

這些要求你需要做到

  • 使用 std::unique_ptr 管理對象生命周期。智能指針是一個好東西,多用用!
  • 保持代碼的可擴展性,方便將來添加新的快餐品牌或漢堡類型。

實現:modern-cpp-patterns-playground/FactoryBaseMethod/BurgerCreator at main · Charliechen114514/modern-cpp-patterns-playground

class AbstractBurger {
public:virtual void grill() = 0;virtual void prepare() = 0;virtual void wrap() = 0;virtual ~AbstractBurger() = default; /* this is required to the parent calss */
};

首先,咱們起手定義了一個抽象基類 AbstractBurger,其中包含了 grill()prepare()wrap() 三個純虛函數,代表了制作漢堡的三個主要步驟。然后,我為麥當勞和漢堡王分別實現了具體的漢堡類,如 McBurgerMcCheeseBurgerBurgerKingBurgerBurgerKingCheeseBurger,每個類都根據品牌和漢堡類型的不同,實現了各自的制作流程。

class BurgerProvider {
public:virtual std::unique_ptr<AbstractBurger> create_specifiedBurger(const std::string& specified_type) = 0;virtual ~BurgerProvider() = default;
};

為了創建這些漢堡對象,我定義了一個抽象工廠類 BurgerProvider,并為每個品牌實現了具體的工廠類 McBurgerProviderBurgerKingProvider。這些工廠類根據傳入的參數(如 “normal” 或 “cheese”)來決定創建哪種具體的漢堡對象。通過這種方式,客戶端代碼可以通過工廠類來創建所需的漢堡,而無需了解具體的實現細節,從而實現了對象創建的解耦。

習題

背景:

您正在開發一個通知發送系統,支持多種通知方式,如電子郵件(Email)、短信(SMS)和推送通知(Push Notification)。每種通知方式有其特定的發送邏輯和所需的參數。

任務:

  1. 定義一個抽象基類 Notification,包含純虛函數 send(const std::string& message)
  2. 實現具體的通知類,如 EmailNotificationSMSNotificationPushNotification,分別繼承自 Notification,并實現發送邏輯。
  3. 創建一個工廠類 NotificationFactory,包含靜態成員函數 createNotification(const std::string& type),根據傳入的類型創建相應的通知對象。
  4. 在主函數中,模擬發送不同類型通知的過程,使用工廠類創建通知對象,并調用其發送方法。

要求:

  • 使用 std::unique_ptr 管理對象生命周期。
  • 考慮每種通知方式所需的特定參數,并在創建對象時傳入。
  • 保持代碼的可擴展性,方便將來添加新的通知方式。

筆者也有自己的實現:modern-cpp-patterns-playground/FactoryBaseMethod/NotificationSystem at main · Charliechen114514/modern-cpp-patterns-playground

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

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

相關文章

MySQL、PostgreSQL、Oracle 區別詳解

MySQL、PostgreSQL、Oracle 區別詳解 一、基礎架構對比 1.1 數據庫類型 MySQL:關系型數據庫(支持NoSQL插件如MySQL Document Store)PostgreSQL:對象-關系型數據庫(支持JSON等半結構化數據)Oracle:多模型數據庫(關系型+文檔+圖+空間等)關鍵結論:PostgreSQL在數據類型…

window11系統 使用GO語言建立TDengine 連接

目錄 1、安裝GCC、TDengine-client 1、github下載mingw64 軟件包 2、解壓指定目錄、配置環境變量 3、檢驗gcc是否安裝成功 4、安裝TDengine-client 2、配置go環境變量 3、配置Goland 系統變量、重啟Goland&#xff08;該軟件自己也有系統變量&#xff0c;有時候會和win…

VR 賦能病毒分離鑒定:開啟微觀探索新視界

在大眾認知里&#xff0c;VR 技術往往與沉浸式游戲體驗、虛擬社交緊密相連&#xff0c;讓人仿佛置身于奇幻的虛擬世界中&#xff0c;感受著科技帶來的奇妙娛樂享受。而病毒分離鑒定&#xff0c;聽起來則是一個充滿專業性與嚴肅性的科學領域&#xff0c;它關乎病毒的研究、疾病的…

Azure Devops pipeline 技巧和最佳實踐

1. 如何顯示release pipeline ? 解決方法: 登錄devops, 找到organization - pipeline - setting下的Disable creation of classic release pipelines,禁用該選項。 然后在project - pipeline - setting,禁用Disable creation of classic release pipelines 現在可以看到r…

GPU的通信技術

GPU 之間直接通信主要采用了以下幾種技術1&#xff1a; GPUDirect P2P&#xff1a;NVIDIA 開發的技術&#xff0c;用于單機上的 GPU 間高速通信。在沒有該技術時&#xff0c;GPU 間數據交換需先通過 CPU 和 PCIe 總線復制到主機固定的共享內存&#xff0c;再復制到目標 GPU&…

重新測試deepseek Jakarta EE 10編程能力

聽說deepseek做了一個小更新&#xff0c;我重新測試了一下Jakarta EE 10編程能力&#xff1b;有點進步&#xff0c;遺漏的功能比以前少了。 采用Jakarta EE 10 編寫員工信息表維護表&#xff0c;包括員工查詢與搜索、員工列表、新增員工、刪除員工&#xff0c;修改員工&#xf…

?Windows 11 安裝 Miniconda 與 Jupyter 全流程指南?

?一、Miniconda 安裝與配置? 1. 下載安裝程序 ?訪問官網?&#xff1a;打開 Miniconda 官網&#xff0c;下載 ?Python 3.x 版本的 Windows 64 位安裝包?。?安裝路徑選擇?&#xff1a; 推薦路徑&#xff1a;D:\Miniconda3&#xff08;避免使用中文路徑和空格&#xff0…

RuoYi前后端分離框架集成手機短信驗證碼(一)之后端篇

一、背景 本項目基于RuoYi 3.8.9前后端分離框架構建,采用Spring Security實現系統權限管理。作為企業級應用架構的子模塊,系統需要與頂層項目實現用戶數據無縫對接(以手機號作為統一用戶標識),同時承擔用戶信息采集的重要職能。為此,我們在保留原有賬號密碼登錄方式的基…

Java ThreadLocal 應用指南:從用戶會話到數據庫連接的線程安全實踐

ThreadLocal 提供了一種線程局部變量&#xff08;thread-local variables&#xff09;的機制&#xff0c;這意味著每個訪問該變量的線程都會擁有其自己獨立的、初始化的變量副本。這確保了線程之間不會共享數據&#xff0c;也避免了因共享數據而可能產生的競爭條件和同步問題&a…

GitCode鏡像門法律分析:PL協議在中國的司法實踐

本文以2022年引發廣泛爭議的GitCode開源代碼鏡像事件為研究對象&#xff0c;系統分析公共許可證&#xff08;Public License&#xff0c;PL&#xff09;在中國法律體系下的適用性挑戰。通過研究中國法院近五年涉及GPL、Apache、MIT等主流協議的21個司法案例&#xff0c;揭示開源…

Rider崩潰問題終極解決指南

JetBrains Rider 2025.1.2 頻繁崩潰問題解決指南 問題描述&#xff1a; 編輯器頻繁自動崩潰&#xff0c;任務管理器顯示大量 Git for Windows 進程被啟動。 原因分析&#xff1a; 這是 Rider 的自動版本控制功能導致的。當檢測到代碼變更時&#xff0c;編輯器會不斷嘗試啟動 …

4 串電池保護芯片創芯微CM1341-DAT使用介紹

特性 專用于 4 串鋰/鐵/鈉電池的保護芯片&#xff0c;內置有高精度電壓檢測電路和電流檢測電路。通過檢測各節電池的電壓、充放電電流及溫度等信息&#xff0c;實現電池過充電、過放電、均衡、斷線、低壓禁充、放電過電流、短路、充電過電流和過溫保護等功能&#xff0c;放電過…

煤礦電液控制器-底座傾角傳感器4K型護套連接器ZE0703-09(100)

煤礦電液控制器作為井下自動化開采的核心設備&#xff0c;其可靠性直接關系到生產安全與效率。在眾多關鍵組件中&#xff0c;底座傾角傳感器4K型護套連接器ZE0703-09&#xff08;100&#xff09;憑借獨特設計成為保障系統穩定運行的"神經末梢"&#xff0c;其技術特性…

Vue計算屬性與監視

在Vue.js中&#xff0c;處理復雜的邏輯和數據依賴關系是構建高效、可維護的前端應用的關鍵。Vue提供了兩種強大的工具來幫助我們實現這一點&#xff1a;計算屬性&#xff08;Computed Properties&#xff09; 和 偵聽器&#xff08;Watchers&#xff09;。本文將深入探討這兩者…

基于RT-Thread的STM32F4開發第七講——RTC(硬件、軟件)

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 前言一、RT-Thread工程創建1.硬件RTC配置2.軟件RTC配置3.RTC鬧鐘配置 總結 前言 本章是基于RT-Thread studio實現RTC硬件和軟件下的日歷時鐘功能&#xff0c;開發板…

Java面試:從Spring Boot到分布式系統的技術探討

場景一&#xff1a;電商平臺的訂單處理 面試官&#xff1a; “謝先生&#xff0c;假設我們在一個電商平臺工作&#xff0c;你將如何使用Spring Boot構建一個訂單處理服務&#xff1f;” 謝飛機&#xff1a; “這個簡單&#xff0c;我會使用Spring Boot快速啟動項目&#xff0…

【Redis】string 類型

string 一. string 類型介紹二. string 命令set、getmget、msetsetnx、setex、psetexincr、incrby、decr、decrby、incrbyfloatappend、getrange、setrange、strlen 三. string 命令小結四. string 內部編碼方式五. string 的應用場景緩存功能計數功能共享會話手機驗證碼 六. 什…

HTTP/HTTPS與SOCKS5三大代理IP協議,如何選擇最佳協議?

在復雜多變的網絡環境中&#xff0c;代理協議的選擇直接影響數據安全、訪問效率和業務穩定性。HTTP、HTTPS和SOCKS5作為三大主流代理協議&#xff0c;各自針對不同場景提供獨特的解決方案。本文將從協議特性、性能對比到選型策略&#xff0c;為您揭示如何根據業務需求精準匹配最…

【ArcGIS Pro微課1000例】0071:將無人機照片生成航線、軌跡點、坐標高程、方位角

文章目錄 一、照片預覽二、生成軌跡點三、照片信息四、查看方位角五、軌跡點連成線一、照片預覽 數據位于配套實驗數據包中的0071.rar,解壓之后如下: 二、生成軌跡點 地理標記照片轉點 (數據管理),用于根據存儲在地理標記照片文件(.jpg 或 .tif)元數據中的 x、y 和 z 坐…

【C++項目】:仿 muduo 庫 One-Thread-One-Loop 式并發服務器

&#x1f308; 個人主頁&#xff1a;Zfox_ &#x1f525; 系列專欄&#xff1a;C從入門到精通 目錄 &#x1f525; 前言 一&#xff1a;&#x1f525; 項目儲備知識 &#x1f98b; HTTP 服務器&#x1f98b; Reactor 模型&#x1f380; 單 Reactor 單線程&#xff1a;單I/O多路…