【C++ 類和數據抽象】消息處理示例(1):從設計模式到實戰應用

目錄

一、數據抽象概述

二、消息處理的核心概念

2.1 什么是消息處理?

2.2 消息處理的核心目標

三、基于設計模式的消息處理實現

3.1 觀察者模式(Observer Pattern)

3.2 命令模式(Command Pattern)

四、實戰場景:GUI 框架中的消息處理

4.1 模擬 Qt 信號槽機制

五、高級主題:多線程消息隊列

5.1 基于隊列的異步消息處理

六、消息處理的最佳實踐

6.1 解耦優先

6.2 線程安全

6.3 錯誤處理

6.4 性能優化

七、總結


在 C++ 的復雜系統開發中,消息處理是實現組件解耦、異步通信和事件驅動的核心機制。無論是 GUI 框架中的按鈕點擊響應,還是分布式系統中的模塊通信,消息處理都扮演著關鍵角色。本文將圍繞設計模式(如觀察者模式、命令模式)和實戰場景(如 GUI 事件、多模塊通信),深入探討 C++ 中消息處理的實現方式。

一、數據抽象概述

數據抽象是一種編程技術,它允許我們定義數據類型,同時隱藏其內部實現細節。意味著,我們只需關注數據對象能做什么,而不是它們是如何做的。在C++中,數據抽象主要通過類和對象實現。類定義了數據成員和成員函數,其中數據成員用于存儲數據,而成員函數用于操作這些數據。通過將數據成員設置為私有(private),確保了它們只能通過類的公共接口(public成員函數)訪問。

數據抽象具有多個優點:

  • 安全性:數據抽象可以防止不恰當的數據訪問,從而保護數據的安全性。
  • 簡化復雜性:允許我們處理復雜系統時,只關注其高層次的抽象,而不是底層細節。
  • 易于維護和修改:由于實現細節被隱藏,修改內部實現時不會影響到使用這些數據的其他部分。
  • 可重用性:抽象數據類型可以被重復使用,從而提高代碼的可重用性。

二、消息處理的核心概念

2.1 什么是消息處理?

消息是組件間傳遞的信息載體,包含事件類型、數據參數等內容。
消息處理指接收消息并執行相應邏輯的過程,通常涉及:

  • 消息發送者:產生消息的組件(如按鈕點擊、傳感器數據更新)。
  • 消息接收者:處理消息的組件(如事件處理器、業務邏輯模塊)。
  • 消息通道:連接發送者與接收者的通信鏈路(如函數調用、隊列、信號槽)。

2.2 消息處理的核心目標

  • 解耦組件:發送者與接收者無需直接依賴,提高系統靈活性。
  • 異步通信:支持非阻塞消息傳遞,提升系統響應速度。
  • 可擴展性:方便添加新的消息類型或處理邏輯。

三、基于設計模式的消息處理實現

3.1 觀察者模式(Observer Pattern)

①模式原理

  • 角色
    • 主題(Subject):維護觀察者列表,發送消息。
    • 觀察者(Observer):接收消息并執行處理邏輯。
  • 核心機制:主題與觀察者通過抽象接口解耦,主題發送消息時自動通知所有注冊的觀察者。

②代碼示例:按鈕點擊事件處理

#include <iostream>
#include <vector>
#include <memory>
#include <algorithm> // 使用 std::remove_if// 抽象觀察者接口
class ButtonObserver {
public:// 純虛函數,具體觀察者需要實現該函數來處理按鈕點擊事件virtual void OnButtonClick() = 0;// 虛析構函數,確保在通過基類指針刪除派生類對象時能正確調用派生類的析構函數virtual ~ButtonObserver() = default;
};// 具體觀察者:日志記錄器
class LogObserver : public ButtonObserver {
public:// 實現 OnButtonClick 函數,處理日志記錄void OnButtonClick() override {std::cout << "Button clicked: Logging event..." << std::endl;}
};// 具體觀察者:業務處理器
class BusinessObserver : public ButtonObserver {
public:// 實現 OnButtonClick 函數,處理業務邏輯void OnButtonClick() override {std::cout << "Button clicked: Processing business logic..." << std::endl;}
};// 主題:按鈕類
class Button {
public:// 向觀察者列表中添加觀察者void AddObserver(std::shared_ptr<ButtonObserver> observer) {if (observer) {observers_.push_back(observer);} else {std::cerr << "Error: Attempt to add a null observer." << std::endl;}}// 從觀察者列表中移除指定的觀察者void RemoveObserver(std::shared_ptr<ButtonObserver> observer) {if (observer) {auto newEnd = std::remove_if(observers_.begin(), observers_.end(), [&observer](const std::shared_ptr<ButtonObserver>& obs) {return obs == observer;});if (newEnd != observers_.end()) {observers_.erase(newEnd, observers_.end());} else {std::cerr << "Error: Observer not found in the list." << std::endl;}} else {std::cerr << "Error: Attempt to remove a null observer." << std::endl;}}// 模擬按鈕點擊,發送消息給所有注冊的觀察者void Click() {std::cout << "Button clicked: Notifying observers..." << std::endl;for (const auto& observer : observers_) {if (observer) {observer->OnButtonClick();} else {std::cerr << "Error: Found a null observer in the list." << std::endl;}}}private:// 存儲觀察者的列表std::vector<std::shared_ptr<ButtonObserver>> observers_;
};// 主函數:測試消息處理流程
int main() {Button button;auto logObserver = std::make_shared<LogObserver>();auto businessObserver = std::make_shared<BusinessObserver>();button.AddObserver(logObserver);button.AddObserver(businessObserver);button.Click(); // 觸發消息發送return 0;
}

3.2 命令模式(Command Pattern)

①模式原理

  • 角色
    • 命令(Command):封裝消息內容和處理邏輯。
    • 調用者(Invoker):觸發命令執行。
    • 接收者(Receiver):實際執行命令的組件。
  • 核心機制:將 “消息” 封裝為命令對象,支持動態添加、撤銷命令,實現異步消息處理。

②代碼示例:文件操作命令隊列

#include <iostream>
#include <vector>
#include <memory>// 抽象命令接口
class FileCommand {
public:virtual void Execute() = 0;virtual ~FileCommand() = default;
};// 具體命令:創建文件
class CreateFileCommand : public FileCommand {
public:CreateFileCommand(const std::string& filename) : filename_(filename) {}void Execute() override {std::cout << "Creating file: " << filename_ << std::endl;// 實際文件創建邏輯}private:std::string filename_;
};// 具體命令:刪除文件
class DeleteFileCommand : public FileCommand {
public:DeleteFileCommand(const std::string& filename) : filename_(filename) {}void Execute() override {std::cout << "Deleting file: " << filename_ << std::endl;// 實際文件刪除邏輯}private:std::string filename_;
};// 命令調用者:消息隊列
class CommandQueue {
public:void AddCommand(std::shared_ptr<FileCommand> command) {commands_.push_back(command);}void ProcessCommands() { // 批量處理消息for (const auto& command : commands_) {command->Execute();}commands_.clear();}private:std::vector<std::shared_ptr<FileCommand>> commands_;
};// 主函數:測試命令模式
int main() {CommandQueue queue;queue.AddCommand(std::make_shared<CreateFileCommand>("data.txt"));queue.AddCommand(std::make_shared<DeleteFileCommand>("temp.txt"));std::cout << "Processing commands..." << std::endl;queue.ProcessCommands();return 0;
}

四、實戰場景:GUI 框架中的消息處理

4.1 模擬 Qt 信號槽機制

Qt 的信號槽機制是 C++ 中消息處理的經典實現,通過元對象系統實現組件間解耦。以下是簡化的模擬實現:

①信號槽核心類

#include <iostream>
#include <vector>
#include <functional>// 信號類:支持綁定槽函數
template <typename... Args>
class Signal {
public:void Connect(std::function<void(Args...)> slot) {slots_.push_back(slot);}void Emit(Args... args) { // 發送消息for (const auto& slot : slots_) {slot(args...);}}private:std::vector<std::function<void(Args...)>> slots_;
};// 按鈕類:發送點擊消息
class GuiButton {
public:Signal<> clicked; // 無參數信號
};// 主函數:模擬GUI消息處理
int main() {GuiButton button;// 綁定槽函數:日志輸出button.clicked.Connect([]() {std::cout << "Button clicked (via signal-slot)!" << std::endl;});// 觸發信號:模擬按鈕點擊std::cout << "Simulating button click..." << std::endl;button.clicked.Emit();return 0;
}

五、高級主題:多線程消息隊列

5.1 基于隊列的異步消息處理

在多線程場景中,消息隊列是實現線程間通信的常用方式。以下是一個簡單的線程安全消息隊列實現:

①線程安全隊列類

#include <iostream>
#include <queue>template <typename T>
class NonThreadSafeQueue {
public:void Enqueue(T message) {queue_.push(std::move(message));}T Dequeue() {T message = queue_.front();queue_.pop();return message;}bool Empty() {return queue_.empty();}private:std::queue<T> queue_;
};// 消息類型定義
struct Message {int type;std::string data;
};// 生產者線程(非線程安全,僅演示邏輯)
void Producer(NonThreadSafeQueue<Message>& queue) {Message msg = {1, "Hello, message queue!"};queue.Enqueue(msg);std::cout << "Producer sent message: " << msg.data << std::endl;
}// 消費者線程(非線程安全,僅演示邏輯)
void Consumer(NonThreadSafeQueue<Message>& queue) {while (!queue.Empty()) {Message msg = queue.Dequeue();std::cout << "Consumer received message: " << msg.data << std::endl;}
}int main() {NonThreadSafeQueue<Message> queue;Producer(queue);Consumer(queue);return 0;
}

六、消息處理的最佳實踐

6.1 解耦優先

  • 使用抽象接口(如觀察者模式中的ButtonObserver)隔離發送者與接收者。
  • 避免硬編碼依賴,通過工廠模式或依賴注入創建消息處理器。

6.2 線程安全

  • 多線程環境中,對共享消息隊列加鎖(如std::mutex)或使用無鎖隊列。
  • 消息對象設計為不可變或線程安全,避免競態條件。

6.3 錯誤處理

為消息處理函數添加異常捕獲,避免未處理異常導致程序崩潰。?

void OnButtonClick() {try {// 消息處理邏輯} catch (const std::exception& e) {std::cerr << "Message handling error: " << e.what() << std::endl;}
}

6.4 性能優化

  • 批量處理消息(如命令模式中的ProcessCommands())減少函數調用開銷。
  • 使用智能指針(如std::shared_ptr)管理消息對象,避免內存泄漏。

七、總結

模式 / 場景核心機制適用場景
觀察者模式主題 - 觀察者訂閱關系GUI 事件、狀態變更通知
命令模式消息封裝為可執行對象撤銷操作、異步任務隊列
信號槽機制動態綁定消息處理器Qt 等 GUI 框架
多線程隊列線程安全的消息傳遞通道跨線程通信、異步任務處理

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

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

相關文章

【Android】自定義Trace

1&#xff0c;Trace分析 Android掉幀分析-CSDN博客 2&#xff0c;自定義Trace 以下&#xff0c;android.os.Trace公開了以下API 1&#xff0c;beginSection與endSection聯合使用&#xff0c;只能在同一個線程 2&#xff0c;beginAsyncSection與endAsyncSection可以在不同線程…

基于tabula對pdf中的excel進行識別并轉換成word(三)

上一節中是基于PaddleOCR對圖片中的excel進行識別并轉換成word優化&#xff0c;本節改變思路&#xff0c;直接從pdf中讀取表格的信息&#xff0c;具體思路如下所述。 PDF中的表格數據如下截圖所示&#xff1a; 一、基于tabula從PDF中提取表格 df_list tabula.read_pdf("…

Java中的接口和抽象類

Java 抽象類與接口&#xff1a;區別、應用與選擇 在 Java 編程的世界里&#xff0c;抽象類和接口是兩個極為重要的概念&#xff0c;它們在實現代碼抽象、提高代碼復用性和可維護性方面發揮著關鍵作用。然而&#xff0c;很多開發者在使用時容易混淆這兩個概念。本文將深入探討 …

Java讀Excel:解析阿里云easyExcel導入文件的行號

文章目錄 引言I 解析阿里云easyExcel導入文件的行號聲明解析對象的基類判斷Excel解析對象類型是否包含繼承某個類 isAssignableFromJava 轉換list類型并設置下標到元素對象屬性II 封裝excel 文件讀取excel 文件讀取用法文件導入上下文III 參數校驗工具類校驗參數是否合法 (jaka…

mmap核心原理和用途及其與內存映射段的關系

mmap 是 Linux/Unix 系統中的一個關鍵系統調用&#xff0c;全稱是 Memory Map&#xff08;內存映射&#xff09;。它的核心功能是將 文件、設備或匿名內存 直接映射到進程的虛擬地址空間&#xff0c;從而實現高效的內存訪問和操作。以下是其核心原理和用途的詳細說明&#xff1…

數據庫概論速成期中版

文章目錄 引論數據庫用戶Casual usersNaive usersApplication programmersDatabase administrators 關系模型CAP數據庫兩種描述關系數據庫的方式簡單總結 第一范式規則第二范式規則舉個例子符合第二規則的操作不符合第二規則的操作 第三范式規則key,superkey,null values,主鍵&…

解決調用Claude 3.7接口 403 Request not allowed問題

1. 遇到問題 Python 基于 Langchain 對接 Claude 3.7 大模型接口進行問答時&#xff0c;由于國內不在Claude支持的國家和地區&#xff0c;所以一直調不通&#xff0c;錯誤 anthropic.PermissionDeniedError: Error code: 403 - {error: {type: forbidden, message: Request…

Vue2+Vue3學習筆記

Vue基礎介紹 下載并安裝vue.js v2 https://v2.cn.vuejs.org/https://v2.cn.vuejs.org/ v3 https://v3.cn.vuejs.org/ 會重定向到Vue.js - 漸進式 JavaScript 框架 | Vue.jsVue.js - 漸進式的 JavaScript 框架https://cn.vuejs.org/ 從v2過渡到v3 在F盤創建v2v3學習筆記 并…

2025年KBS新算法 SCI1區TOP:長穎燕麥優化算法AOO,深度解析+性能實測

目錄 1.摘要2.算法原理3.結果展示4.參考文獻5.文章&代碼獲取 1.摘要 本文提出了一種新穎的元啟發式算法——長穎燕麥優化算法&#xff08;AOO&#xff09;&#xff0c;該算法靈感來自動畫燕麥在環境中的自然行為。AOO模擬了長穎燕麥的三種獨特行為&#xff1a;(i) 通過自然…

CentosLinux系統crontab發現執行刪除命令失效解決方法

權限或安全策略限制 ??可能場景??&#xff1a; ??### ??目錄權限沖突??&#xff1a; 你的目錄權限為 drwxr-xr-x&#xff08;屬主 mssql&#xff09;&#xff0c;但 cron 任務以 root 執行。 ??風險點??&#xff1a;若目錄內文件屬主為 mssql 且權限為 700&…

后驗概率最大化(MAP)估計算法原理以及相具體的應用實例附C++代碼示例

1. MAP估計基本原理 MAP&#xff08;Maximum A Posteriori&#xff0c;最大后驗概率估計&#xff09;是貝葉斯推斷中的重要概念&#xff0c;它的目標是&#xff1a; 給定觀測數據&#xff0c;找到使得后驗概率最大的參數值。 公式化表示&#xff1a; [ θ MAP arg ? max ?…

16、路由守衛:設置魔法結界——React 19 React Router

一、魔法結界的本質 "路由守衛是霍格沃茨城堡的隱身斗篷&#xff0c;在時空裂隙中精準控制維度躍遷&#xff01;" 魔法部交通司官員揮舞魔杖&#xff0c;React Router 的嵌套路由在空中交織成星軌矩陣。 ——基于《國際魔法聯合會》第7號時空協議&#xff0c;路由守…

從車道檢測項目入門open cv

從車道檢測項目入門open cv 前提聲明&#xff1a;非常感謝b站up主 嘉然今天吃帶變&#xff0c;感謝其視頻的幫助。同時希望各位大佬積積極提出寶貴的意見。&#x1f60a;&#x1f60a;&#x1f60a;(???)(●’?’●)╰(▽)╯ github地址&#xff1a;https://github.com/liz…

【行業特化篇3】制造業簡歷優化指南:技術參數與標準化流程的關鍵詞植入藝術

寫在最前 作為一個中古程序猿,我有很多自己想做的事情,比如埋頭苦干手搓一個低代碼數據庫設計平臺(目前只針對寫java的朋友),比如很喜歡幫身邊的朋友看看簡歷,講講面試技巧,畢竟工作這么多年,也做到過高管,有很多面人經歷,意見還算有用,大家基本都能拿到想要的offe…

如何在本地部署小智服務器:從源碼到全模塊運行的詳細步驟

小智聊天機器人本地后臺服務器源碼全模塊部署 作者&#xff1a;林甲酸 -不是小女子也不是女漢子 是大女子 更新日期&#xff1a;2025年4月29日 &#x1f3af; 前言&#xff1a;為什么要寫這篇教程&#xff1f; 上周按照蝦哥小智服務器的教程去部署本地后臺&#xff0c;我用的是…

github開源項目添加開源協議,使用很簡單

直接在 GitHub 網頁上創建 進入你的 GitHub 倉庫 打開你的項目倉庫頁面&#xff08;如 https://github.com/用戶名/倉庫名&#xff09;。 點擊 "Add file" → "Create new file" 在倉庫主頁&#xff0c;點擊右上角的 "Add file" 按鈕&#xff…

8.idea創建maven項目(使用Log4j日志記錄框架+Log4j 介紹)

8.idea創建maven項目(使用Log4j日志記錄框架Log4j 介紹) 在 IntelliJ IDEA 的 Maven 項目中引入了 Log4j&#xff0c;并配置了日志同時輸出到控制臺和文件。 Log4j 提供了靈活的日志配置選項&#xff0c;可以根據項目需求調整日志級別、輸出目標和格式。 1. 創建 Maven 項目 …

【和春筍一起學C++】函數——C++的編程模塊

目錄 1. 原型句法 2. 函數分類 3. 函數參數之按值傳遞 4. 數組作為函數參數 在C中&#xff0c;要使用函數&#xff0c;必須要有這三個方面&#xff1a; 函數原型&#xff0c;函數原型描述了函數到編譯器的接口&#xff0c;函數原型一般放在include文件中。函數原型告訴編譯…

深挖Java基礎之:認識Java(創立空間/先導:Java認識)

今天我要介紹的是在Java中對Java的一些基本語法的認識與他們的運用&#xff0c;以及擬舉例子說明和運用場景&#xff0c;優勢和劣勢&#xff0c; 注&#xff1a;本篇文章是對Java的一些基本的&#xff0c;簡單的代碼塊的一些內容&#xff0c;后續會講解在Java中的變量類型&…

Python+Selenium+Pytest+Allure PO模式UI自動化框架

一、框架結構 allure-report&#xff1a;測試報告base&#xff1a;定位元素封裝data&#xff1a;數據log&#xff1a;日志文件page&#xff1a;頁面封裝文件夾report&#xff1a;緩存報告testcases&#xff1a;測試用例層utils&#xff1a;工具類run.py&#xff1a;執行文件 二…