深入解析 C++ 設計模式:原理、實現與應用

一、引言

????????在 C++ 編程的廣袤領域中,設計模式猶如閃耀的燈塔,為開發者指引著構建高效、可維護軟件系統的方向。設計模式并非神秘莫測的代碼魔法,實際上,我們在日常編程中或許早已與之打過交道。簡單來說,設計模式常常借助多態這一強大特性,達成各式各樣不同的操作方式。多態使得我們能夠以統一的接口來應對不同類型的對象,為設計模式的實現筑牢了根基。接下來,讓我們深入探索幾種常見的設計模式。

二、策略模式

(一)模式概述

????????策略模式包含一組策略類以及一個決策者類。其中,這組策略類是一系列繼承自同一個基類的類。策略類承擔著實現豐富多樣不同策略的職責,而決策者類則負責挑選合適的策略并予以執行。

(二)代碼實現

// 策略基類,定義了一個純虛函數 move,任何繼承自此類的子類都必須實現該函數
// 此基類為所有具體的移動策略提供了統一的接口
class MovementStrategy {
public:// 純虛函數,用于執行具體的移動操作virtual void move() = 0;// 虛析構函數,確保在通過基類指針刪除派生類對象時,能正確調用派生類的析構函數virtual ~MovementStrategy() {}
};// 步行策略類,繼承自 MovementStrategy 基類
// 該類實現了步行這種具體的移動策略
class WalkStrategy : public MovementStrategy {
public:// 重寫基類的 move 函數,實現步行操作的具體邏輯void move() override {std::cout << "Character is walking." << std::endl;}
};// 跑步策略類,繼承自 MovementStrategy 基類
// 該類實現了跑步這種具體的移動策略
class RunStrategy : public MovementStrategy {
public:// 重寫基類的 move 函數,實現跑步操作的具體邏輯void move() override {std::cout << "Character is running." << std::endl;}
};// 決策者類,負責選擇和執行具體的移動策略
class Character {
private:// 指向當前使用的移動策略對象的指針MovementStrategy* currentStrategy;
public:// 構造函數,初始化角色的移動策略Character(MovementStrategy* strategy) : currentStrategy(strategy) {}// 設置角色的移動策略void setStrategy(MovementStrategy* strategy) {currentStrategy = strategy;}// 調用當前移動策略的 move 函數,執行移動操作void move() {currentStrategy->move();}// 析構函數,釋放當前使用的移動策略對象所占用的內存~Character() {delete currentStrategy;}
};

(三)工作原理與實現邏輯

  1. 策略基類MovementStrategy作為策略基類,定義了純虛函數move。這就為所有具體的移動策略(如步行、跑步等)制定了統一的接口規范。任何繼承自該基類的子類都必須實現move函數,以提供具體的策略實現。同時,虛析構函數確保在通過基類指針刪除派生類對象時,能夠正確調用派生類的析構函數,避免內存泄漏。
  2. 具體策略類WalkStrategyRunStrategy分別繼承自MovementStrategy基類。它們通過重寫move函數,實現了各自獨特的移動策略。WalkStrategymove函數輸出 “Character is walking.”,表示角色正在步行;RunStrategymove函數輸出 “Character is running.”,表示角色正在跑步。
  3. 決策者類Character類作為決策者類,持有一個指向MovementStrategy對象的指針currentStrategy。在構造函數中,通過傳入具體的策略對象來初始化currentStrategysetStrategy函數用于動態更改角色當前使用的移動策略。move函數則調用currentStrategy所指向對象的move函數,從而執行當前選定的移動策略。在析構函數中,釋放currentStrategy所指向的對象,以確保內存的正確管理。

三、代理模式

(一)模式概述

????????代理模式僅需一組類,但這組類包含兩個具有不同功能的角色,即被代理者和代理者。

(二)代碼實現

// 被代理類(遠程數據庫訪問類)
// 該類負責實際從遠程數據庫獲取數據
class RemoteDatabase {
public:// 獲取遠程數據庫數據的函數std::string getData() {std::cout << "Accessing remote database..." << std::endl;return "Data from remote database";}
};// 代理類,用于代理對遠程數據庫的訪問
// 引入緩存機制,減少對遠程數據庫的頻繁訪問
class DatabaseProxy {
private:// 指向被代理的遠程數據庫對象的指針RemoteDatabase* realDatabase;// 緩存從遠程數據庫獲取的數據std::string cachedData;// 標記數據是否已緩存bool isCached;
public:// 構造函數,初始化被代理對象和緩存標記DatabaseProxy() : realDatabase(new RemoteDatabase), isCached(false) {}// 獲取數據的函數,優先從緩存中獲取,若緩存中沒有則從遠程數據庫獲取并緩存std::string getData() {if (isCached) {return cachedData;}cachedData = realDatabase->getData();isCached = true;return cachedData;}// 析構函數,釋放被代理對象所占用的內存~DatabaseProxy() {delete realDatabase;}
};

(三)工作原理與實現邏輯

  1. 被代理類RemoteDatabase類代表被代理的遠程數據庫訪問對象。其getData函數用于從遠程數據庫獲取數據,并在獲取過程中輸出 “Accessing remote database...”,表示正在訪問遠程數據庫,最后返回從數據庫獲取到的數據。
  2. 代理類DatabaseProxy類作為代理者,內部持有一個指向RemoteDatabase對象的指針realDatabase,以及用于緩存數據的cachedData和標記數據是否已緩存的isCached。在構造函數中,創建RemoteDatabase對象并初始化isCachedfalsegetData函數是代理模式的核心邏輯所在,首先檢查isCached是否為true,若為true,則直接返回緩存中的數據cachedData,避免了再次訪問遠程數據庫;若為false,則調用realDatabasegetData函數從遠程數據庫獲取數據,將獲取到的數據存入cachedData并將isCached設為true,最后返回數據。在析構函數中,釋放realDatabase所指向的對象,確保內存的正確釋放。

四、簡單工廠模式

(一)模式概述

????????簡單工廠模式下存在兩組類,一組是產品類,另一組是工廠類。產品類包含各種各樣不同的產品,每個產品能執行不同的任務。工廠類則依據提供的不同 “原材料”,生產出相應的產品。

(二)代碼實現

// 產品基類,定義了一個純虛函數 getResult,任何繼承自此類的子類都必須實現該函數
// 此基類為所有具體的計算產品提供了統一的接口
class Operation {
public:// 純虛函數,用于執行具體的計算操作并返回結果virtual int getResult(int num1, int num2) = 0;// 虛析構函數,確保在通過基類指針刪除派生類對象時,能正確調用派生類的析構函數virtual ~Operation() {}
};// 加法運算類,繼承自 Operation 基類
// 該類實現了加法計算這種具體的產品功能
class OperationAdd : public Operation {
public:// 重寫基類的 getResult 函數,實現加法計算的具體邏輯int getResult(int num1, int num2) override {return num1 + num2;}
};// 減法運算類,繼承自 Operation 基類
// 該類實現了減法計算這種具體的產品功能
class OperationSub : public Operation {
public:// 重寫基類的 getResult 函數,實現減法計算的具體邏輯int getResult(int num1, int num2) override {return num1 - num2;}
};// 工廠類,負責根據傳入的操作符生產相應的計算產品對象
class OperationFactory {
public:// 靜態工廠方法,根據傳入的操作符創建對應的計算產品對象static Operation* createOperation(const std::string& operate) {if (operate == "+") {return new OperationAdd;} else if (operate == "-") {return new OperationSub;}return nullptr;}
};

(三)工作原理與實現邏輯

  1. 產品基類Operation作為產品基類,定義了純虛函數getResult,用于執行具體的計算操作并返回結果。這為所有具體的計算產品(如加法、減法等)提供了統一的接口。任何繼承自該基類的子類都必須實現getResult函數,以實現各自特定的計算功能。同時,虛析構函數確保在通過基類指針刪除派生類對象時,能夠正確調用派生類的析構函數,防止內存泄漏。
  2. 具體產品類OperationAddOperationSub分別繼承自Operation基類。它們通過重寫getResult函數,實現了各自的計算邏輯。OperationAddgetResult函數將傳入的兩個數相加并返回結果,OperationSubgetResult函數則將兩個數相減并返回結果。
  3. 工廠類OperationFactory類作為工廠類,提供了一個靜態的createOperation方法。該方法接收一個表示操作符的字符串operate作為參數,根據operate的值判斷需要創建的產品類型。如果operate為 “+”,則創建一個OperationAdd對象并返回;如果operate為 “-”,則創建一個OperationSub對象并返回;若傳入的操作符不匹配任何已知的操作,則返回nullptr。這種方式使得產品的創建邏輯集中在工廠類中,方便管理和維護。

(四)優缺點

  • 優點:邏輯簡單直白,易于理解和實現。對于簡單的對象創建場景,使用簡單工廠模式可以快速搭建起系統的對象創建框架。
  • 缺點:違反 “開閉原則”。當需要添加新的產品類(如乘法、除法運算類)時,必須修改工廠類的createOperation方法,添加新的條件判斷邏輯。這不僅增加了修改現有代碼的風險,還可能導致其他依賴該工廠類的代碼出現問題,不利于系統的維護和拓展。

五、工廠方法模式

(一)模式概述

????????工廠方法模式同樣包含一組產品類和一組工廠類。該模式旨在解決簡單工廠模式違反開閉原則的問題,它將每個產品都對應到一個獨立的工廠類去生產,即每個工廠只能生產一種產品。

(二)代碼實現

// 產品基類,定義了一個純虛函數 getResult,任何繼承自此類的子類都必須實現該函數
// 此基類為所有具體的計算產品提供了統一的接口
class Operation {
public:// 純虛函數,用于執行具體的計算操作并返回結果virtual int getResult(int num1, int num2) = 0;// 虛析構函數,確保在通過基類指針刪除派生類對象時,能正確調用派生類的析構函數virtual ~Operation() {}
};// 加法運算類,繼承自 Operation 基類
// 該類實現了加法計算這種具體的產品功能
class OperationAdd : public Operation {
public:// 重寫基類的 getResult 函數,實現加法計算的具體邏輯int getResult(int num1, int num2) override {return num1 + num2;}
};// 減法運算類,繼承自 Operation 基類
// 該類實現了減法計算這種具體的產品功能
class OperationSub : public Operation {
public:// 重寫基類的 getResult 函數,實現減法計算的具體邏輯int getResult(int num1, int num2) override {return num1 - num2;}
};// 加法工廠類,專門用于生產加法運算對象
class AddFactory {
public:// 靜態工廠方法,創建并返回一個加法運算對象static Operation* createOperation() {return new OperationAdd;}
};// 減法工廠類,專門用于生產減法運算對象
class SubFactory {
public:// 靜態工廠方法,創建并返回一個減法運算對象static Operation* createOperation() {return new OperationSub;}
};

(三)工作原理與實現邏輯

  1. 產品基類與具體產品類:這部分與簡單工廠模式類似,Operation作為產品基類定義了統一的接口getResultOperationAddOperationSub等具體產品類繼承自Operation基類,并實現了各自的計算邏輯。
  2. 工廠類:在工廠方法模式中,每個產品都有對應的工廠類。AddFactory專門用于創建OperationAdd對象,其createOperation方法返回一個新的OperationAdd實例;SubFactory專門用于創建OperationSub對象,其createOperation方法返回一個新的OperationSub實例。當需要添加新的產品類(如乘法運算類OperationMul)時,只需創建對應的工廠類(如MulFactory),并在其中實現創建OperationMul對象的邏輯,而無需修改現有的工廠類代碼,從而遵循了開閉原則。

(四)優缺點

  • 缺點:前期代碼量大,因為每一個產品都需要一個獨立工廠去生產,這無疑增加了代碼的編寫量和維護成本。例如,若有多種不同類型的計算產品,就需要創建同樣數量的工廠類。
  • 優點:遵循了開閉原則,易于維護拓展。當系統需要添加新的產品時,只需創建新的產品類和對應的工廠類,而不會影響到現有的代碼。同時,獨立工廠生產能夠方便地進行定制化,比如可以在工廠類中添加特定的初始化邏輯或資源分配邏輯,以滿足不同產品的特殊需求。

六、抽象工廠模式

(一)模式概述

????????抽象工廠模式包含多組產品類和一組工廠類。工廠類能夠生產多個產品,并且不同的工廠生產的產品品牌不同。

(二)代碼實現

// 空調抽象類,定義了一個純虛函數 showInfo,任何繼承自此類的子類都必須實現該函數
// 此基類為所有具體品牌的空調產品提供了統一的接口
class AirConditioner {
public:// 純虛函數,用于展示空調的信息virtual void showInfo() = 0;// 虛析構函數,確保在通過基類指針刪除派生類對象時,能正確調用派生類的析構函數virtual ~AirConditioner() {}
};// 美的空調類,繼承自 AirConditioner 基類
// 該類實現了美的品牌空調的具體信息展示功能
class MideaAirConditioner : public AirConditioner {
public:// 重寫基類的 showInfo 函數,展示美的空調的信息void showInfo() override {std::cout << "This is Midea air conditioner." << std::endl;}
};// 格力空調類,繼承自 AirConditioner 基類
// 該類實現了格力品牌空調的具體信息展示功能
class GreeAirConditioner : public AirConditioner {
public:// 重寫基類的 showInfo 函數,展示格力空調的信息void showInfo() override {std::cout << "This is Gree air conditioner." << std::endl;}
};// 電冰箱抽象類,定義了一個純虛函數 showInfo,任何繼承自此類的子類都必須實現該函數
// 此基類為所有具體品牌的電冰箱產品提供了統一的接口
class Refrigerator {
public:// 純虛函數,用于展示電冰箱的信息virtual void showInfo() = 0;// 虛析構函數,確保在通過基類指針刪除派生類對象時,能正確調用派生類的析構函數virtual ~Refrigerator() {}
};// 美的電冰箱類,繼承自 Refrigerator 基類
// 該類實現了美的品牌電冰箱的具體信息展示功能
class MideaRefrigerator : public Refrigerator {
public:// 重寫基類的 showInfo 函數,展示美的電冰箱的信息void showInfo() override {std::cout << "This is Midea refrigerator." << std::endl;}
};// 格力電冰箱類,繼承自 Refrigerator 基類
// 該類實現了格力品牌電冰箱的具體信息展示功能
class GreeRefrigerator : public Refrigerator {
public:// 重寫基類的 showInfo 函數,展示格力電冰箱的信息void showInfo() override {std::cout << "This is Gree refrigerator." << std::endl;}

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

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

相關文章

Python刷題筆記

Python刷題筆記 1、輸出格式化 第一種格式化的輸出&#xff1a; name "jack" age 17 salary 20031.8752 print("你的名字是&#xff1a;%s,今年 %d 歲,工資 %7.2f" % (name,age,salary) ) --------------------------------------- 你的名字是&#…

【Kubernetes】Kubernetes 如何進行日志管理?Fluentd / Loki / ELK 適用于什么場景?

由于 Kubernetes 運行在容器化的環境中&#xff0c;應用程序和系統日志通常分布在多個容器和節點上&#xff0c;傳統的日志管理方法&#xff08;例如直接訪問每個節點的日志文件&#xff09;在 Kubernetes 中不適用。 因此&#xff0c;Kubernetes 引入了集中式日志管理方案&am…

Ansible(8)——循環與條件任務

目錄 一、循環迭代任務&#xff1a; 1、簡單循環&#xff1a; 2、循環字典列表&#xff1a; 3、Ansible 2.5 之前的循環關鍵字&#xff1a; 4、在循環中使用 register 變量&#xff1a; 二、條件任務&#xff1a; 1、使用條件句的常見場景&#xff1a; 2、條件任務語法…

adb|scrcpy的安裝和配置方法|手機投屏電腦|手機聲音投電腦|adb連接模擬器或手機

adb|scrcpy的安裝和配置方法手機投屏電腦|手機聲音投電腦|adb連接模擬器或手機或電視 引言 在數字設備交織的現代生活中&#xff0c;adb&#xff08;Android Debug Bridge&#xff09;與 scrcpy 宛如隱匿的強大工具&#xff0c;極大地拓展了我們操控手機、模擬器乃至智能電視等…

vue3項目集成electron

一、環境準備 1. 確保已安裝 Node.js (建議版本 16.x 或更高) 2. 創建或進入現有 Vue 項目目錄 cd your-vue-project 二、添加 Electron 支持 在項目根目錄執行: vue add electron-builder 執行后會在 `src` 目錄下生成 `background.js` 主進程文件。 三、主進程配置 (ba…

循環神經網絡 - 參數學習之隨時間反向傳播算法

本文中&#xff0c;我們以同步的序列到序列模式為例來介紹循環神經網絡的參數學習。 循環神經網絡中存在一個遞歸調用的函數 &#x1d453;(?)&#xff0c;因此其計算參數梯度的方式和前饋神經網絡不太相同。在循環神經網絡中主要有兩種計算梯度的方式&#xff1a;隨時間反向…

體驗OceanBase的 并行導入功能

在數據庫的日常使用中&#xff0c;會經常遇到以下場景&#xff1a; ?數據復制?&#xff1a;將一個或多個表中的數據復制到目標表中&#xff0c;可能是復制全部數據&#xff0c;也可能僅復制部分數據。數據合并&#xff1a;將數據從一個表轉移到另一個表&#xff0c;或者將多…

Kafka和RocketMQ相比有什么區別?那個更好用?

Kafka和RocketMQ相比有什么區別?那個更好用? Kafka 和 RocketMQ 都是廣泛使用的消息隊列系統&#xff0c;它們有很多相似之處&#xff0c;但也有一些關鍵的區別。具體選擇哪個更好用&#xff0c;要根據你的應用場景和需求來決定。以下是它們之間的主要區別&#xff1a; 1. …

UniApp 實現兼容 H5 和小程序的拖拽排序組件

如何使用 UniApp 實現一個兼容 H5 和小程序的 九宮格拖拽排序組件&#xff0c;實現思路和關鍵步驟。 一、實現目標 支持拖動菜單項改變順序拖拽過程實時預覽移動位置拖拽松開后自動吸附回網格兼容 H5 和小程序平臺 二、功能結構拆解以及完整代碼 完整代碼&#xff1a; <…

[raspberrypi 0w and respeaker 2mic]實時音頻波形

0. 環境 ubuntu22主機&#xff0c; 192.168.8.162&#xff0c; raspberry 0w&#xff0c; 192.168.8.220 路由器 1. 樹莓派 # rpi - send.py # 或者命令行&#xff1a;arecord -D plughw:1,0 -t wav -f cd -r 16000 -c 2 | nc 192.168.8.162 12345import socket imp…

公司內部建立apt源

有一篇建立pypi源的在這里需要的可以查看&#xff1a;公司內部建立pypi源-CSDN博客 背景&#xff0c;公司內部有很多工具僅供內部使用&#xff0c;如果用apt的方式就比較方便&#xff0c;只需要修改sources.list將源添加進去就可以了。我們接下來的操作就是為了實現這個需求。…

UE5中如何修復后處理動畫藍圖帶來的自然狀態下的metablriger身體綁定形變(如聳肩)問題

【[metablriger] UE5中如何修復后處理動畫藍圖帶來的自然狀態下的metablriger身體綁定形變(如聳肩)問題】 UE5中如何修復后處理動畫藍圖帶來的自然狀態下的metablriger身體綁定形變(如聳肩)問題

AWS Bedrock生成視頻詳解:AI視頻創作新時代已來臨

?? TL;DR: AWS Bedrock現已支持AI視頻生成功能,讓企業無需深厚AI專業知識即可創建高質量視頻內容。本文詳解Bedrock視頻生成能力的工作原理、應用場景和實操指南,助你快速掌握這一革命性技術。 ?? AWS Bedrock視頻生成:改變內容創作的游戲規則 還記得幾年前,制作一個專…

1.2 測試設計階段:打造高質量的測試用例

測試設計階段&#xff1a;打造高質量的測試用例 摘要 本文詳細介紹了軟件測試流程中的測試設計階段&#xff0c;包括測試用例設計、測試數據準備、測試環境搭建和測試方案設計等內容。通過本文&#xff0c;讀者可以系統性地了解測試設計的方法和技巧&#xff0c;掌握如何高效…

jQueryHTML與插件

1.jQuery 事件機制 1.1 注冊事件 bind()、on()方法向被選元素添加一個或多個事件處理程序&#xff0c;以及當事件發生時運行的函數 $("p").on({"click": function () {alert("點擊了")},"mouseenter": function () {…

MySQL 觸發器與存儲過程:數據庫的自動化工廠

在數據世界的工業區&#xff0c;有一座運轉高效的自動化工廠&#xff0c;那里的機器人日夜不停地處理數據…這就是 MySQL 的觸發器與存儲過程系統&#xff0c;它讓數據庫從"手工作坊"變成了"現代化工廠"… 什么是 MySQL 觸發器與存儲過程&#xff1f;&…

PostgreSQL-中文字段排序-修改字段的排序規則

最新版本更新 https://code.jiangjiesheng.cn/article/365?fromcsdn 推薦 《高并發 & 微服務 & 性能調優實戰案例100講 源碼下載》 -- 修改字段的排序規則 ALTER TABLE "public"."your_table_name" ALTER COLUMN "name" TYPE varcha…

GitHub優秀項目:數據湖的管理系統LakeFS

lakeFS 是一個開源工具&#xff0c;它將用戶的對象存儲轉換為類似Git的存儲庫。使用戶可以像管理代碼一樣管理數據湖。借助 lakeFS&#xff0c;可以構建可重復、原子化和版本化的數據湖操作--從復雜的ETL作業到數據科學和分析。 Stars 數11090Forks 數3157 主要特點 強大的數據…

頁面編輯器CodeMirror初始化不顯示行號或文本內容

延遲刷新 本來想延遲100毫秒的&#xff0c;但是會出現樣式向左偏移的情況&#xff0c;于是試了試500毫秒&#xff0c;發現就沒有問題了&#xff0c;可能是樣式什么是需要一個加載過程吧。 useEffect(() > {editorRef.current?.setValue(value || );setTimeout(() > {edi…

使用 Spring Boot 和 Uniapp 搭建 NFC 讀取系統

目錄 一、NFC 技術原理大揭秘1.1 NFC 簡介1.2 NFC 工作原理1.3 NFC 應用場景 二、Spring Boot 開發環境搭建2.1 創建 Spring Boot 項目2.2 項目基本配置 三、Spring Boot 讀取 NFC 數據3.1 NFC 設備連接與初始化3.2 數據讀取邏輯實現3.3 數據處理與存儲 四、Uniapp 前端界面開發…