從C++編程入手設計模式——觀察者模式

從C++編程入手設計模式——觀察者模式

? 觀察者模式簡直就是字如其名,觀察觀察,觀察到了告訴別人。觀察手的作用如此,觀察者模式的工作機制也是如此。這個模式的核心思路是:一個對象的狀態發生變化時,自動通知依賴它的其他對象,讓它們自行更新

主要的組成部分

一是被觀察者,也叫主題(Subject),它負責記錄觀察者并在自身狀態發生變化時通知它們;換而言之,Subject作為信息的生成端,生成信息。

二是觀察者(Observer),它主動注冊到被觀察者中,等待被通知,一旦收到消息就立即采取行動。這里生成端會使用遠程的方式通知我們的被觀察者投送信息。

? 你可以把觀察者模式想象成“訂閱報紙”。報社就是主題,它維護一個訂閱者名單(觀察者列表)。每當有新一期的報紙(數據更新)出版時,它就向所有訂閱者投遞(通知)。每位訂閱者收到報紙后根據自己的需要決定怎么處理,是直接閱讀、剪報存檔還是轉發朋友。這種發布-訂閱機制就是觀察者模式的最基本形式。


在 C++ 中怎么寫?

觀察者模式的代碼實現非常自然。我們會先定義一個抽象的觀察者接口(通常叫 Observer 或者 Sender),讓不同的具體觀察者實現它;再定義一個主題類(通常叫 SubjectNotifier),它包含一個觀察者列表,并負責注冊、移除和通知觀察者。每當主題內部數據變化(比如溫度、濕度更新),它就會遍歷觀察者列表,挨個調用它們的“更新方法”。觀察者模式的重點不在于通知的“數據內容”本身,而在于自動通知的機制


選擇觀察者模式?

在簡單的程序中,我們可能會直接調用某些對象來執行邏輯。但如果程序復雜起來,比如某個數據更新后要引發十幾種操作,硬編碼這些調用就會讓系統結構僵硬,維護困難。

觀察者模式將“變化的主體”和“依賴的反應者”解耦。被觀察者不用關心觀察者是誰,它只管發出通知。觀察者自己決定是否接收通知、如何響應。這讓系統的擴展性和靈活性大大提高

比如天氣系統中新加一個“語音播報設備”,只要實現觀察者接口并注冊進去,其他部分代碼幾乎無需改動。


觀察者模式的幾個關鍵詞

  1. 低耦合:主題和觀察者之間不互相依賴,只通過接口通信。
  2. 自動同步:當主題數據變化時,所有觀察者自動得到通知。
  3. 一對多:一個主題可以對應多個觀察者。
  4. 注冊/注銷機制:觀察者可以自由加入或離開通知流程。

Example

? 可以直接看一個代碼框架來解決問題

#include <iostream>
#include <vector>
#include <memory>
#include <string>
#include <algorithm>// 觀察者接口
class Observer {
public:virtual void update(const std::string& message) = 0;virtual ~Observer() = default;
};// 具體觀察者
class ConcreteObserver : public Observer {
private:std::string name;
public:explicit ConcreteObserver(std::string n) : name(std::move(n)) {}void update(const std::string& message) override {std::cout << "Observer [" << name << "] received: " << message << '\n';}
};// 主題接口
class Subject {
public:virtual void attach(std::shared_ptr<Observer> observer) = 0;virtual void detach(std::shared_ptr<Observer> observer) = 0;virtual void notify(const std::string& message) = 0;virtual ~Subject() = default;
};// 具體主題
class ConcreteSubject : public Subject {
private:std::vector<std::shared_ptr<Observer>> observers;
public:void attach(std::shared_ptr<Observer> observer) override {observers.push_back(std::move(observer));}void detach(std::shared_ptr<Observer> observer) override {observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());}void notify(const std::string& message) override {for (const auto& observer : observers) {observer->update(message);}}
};int main() {auto subject = std::make_shared<ConcreteSubject>();auto obs1 = std::make_shared<ConcreteObserver>("Observer1");auto obs2 = std::make_shared<ConcreteObserver>("Observer2");subject->attach(obs1);subject->attach(obs2);subject->notify("Event 1 occurred");subject->detach(obs1);subject->notify("Event 2 occurred");return 0;
}

? 你可以使用這樣的方式來作為事件驅動框架的一個根基。

練習題

天氣站系統

要求:設計一個天氣數據發布系統,天氣站(WeatherStation)是“主題”,可通知多個“觀察者”顯示設備(如手機、網頁等)。

功能要求

  1. 觀察者可以注冊/注銷。
  2. 當溫度或濕度變化時,所有注冊觀察者會收到更新并打印數據。(注:這個部分筆者的參考代碼沒有實現,您自己酌情思考)

提示

  • 使用接口 IObserver 表示觀察者,定義如 update(float temperature, float humidity)
  • 主題接口 ISubject 需要支持 registerObserver()removeObserver()notifyObservers()
  • 可以實現兩個觀察者類 PhoneDisplayWebDisplay

modern-cpp-patterns-playground/Observer/WeatherForecast at main · Charliechen114514/modern-cpp-patterns-playground

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

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

相關文章

MITM 中間人攻擊

?據Akamai 2023網絡安全報告顯示&#xff0c;MITM攻擊在數據泄露事件中占比達32.7%&#xff0c;平均每次事件造成企業損失$380,000? ?NIST研究指出&#xff1a;2022-2023年高級MITM攻擊增長41%&#xff0c;近70%針對金融和醫療行業? 一、MITM攻擊核心原理與技術演進 1. 中…

llama_index chromadb實現RAG的簡單應用

此demo是自己提的一個需求&#xff1a;用modelscope下載的本地大模型實現RAG應用。畢竟大模型本地化有利于微調&#xff0c;RAG使內容更有依據。 為什么要用RAG&#xff1f; 由于大模型存在一定的局限性&#xff1a;知識時效性不足、專業領域覆蓋有限以及生成結果易出現“幻覺…

TDMQ CKafka 版事務:分布式環境下的消息一致性保障

解鎖 CKafka 事務能力的神秘面紗 在當今數字化浪潮下&#xff0c;分布式系統已成為支撐海量數據處理和高并發業務的中流砥柱。但在這看似堅不可摧的架構背后&#xff0c;數據一致性問題卻如影隨形&#xff0c;時刻考驗著系統的穩定性與可靠性。 CKafka 作為分布式流處理平臺的…

常見的負載均衡算法

常見的負載均衡算法 在實現水平擴展過程中&#xff0c;負載均衡算法是決定請求如何在多個服務實例間分配的核心邏輯。一個合理的負載均衡策略能夠有效分散系統壓力&#xff0c;提升系統吞吐能力與穩定性。 負載均衡算法可部署在多種層級中&#xff0c;如七層HTTP反向代理&…

數據結構轉換與離散點生成

在 C 開發中&#xff0c;我們常常需要在不同的數據結構之間進行轉換&#xff0c;以滿足特定庫或框架的要求。本文將探討如何將 std::vector<gp_Pnt> 轉換為 QVector<QPointF>&#xff0c;并生成特定范圍內的二維離散點。 生成二維離散點 我們首先需要生成一系列…

零基礎學習Redis(12) -- Java連接redis服務器

在我們之前的內容中&#xff0c;我們會發現通過命令行操作redis是十分不科學的&#xff0c;所以redis官方提供了redis的應用層協議RESP&#xff0c;更具這個協議可以實現一個和redis服務器通信的客戶端程序&#xff0c;來簡化和完善redis的使用。現階段有很多封裝了RESP協議的庫…

clangd LSP 不能找到項目中的文件

clangd LSP 不能找到項目中的文件 clangd LSP 不能找到項目中的文件 clangd LSP 不能找到項目中的文件 Normally you need to create compile_commands.json。 如果你使用 cmake 作為構建工具&#xff0c;請執行下面的命令&#xff1a; cmake -DCMAKE_EXPORT_COMPILE_COMMAN…

【內存】Linux 內核優化實戰 - vm.overcommit_memory

目錄 vm.overcommit_memory 解釋一、概念與作用二、參數取值與含義三、相關參數與配置方式四、實際應用場景建議五、注意事項 vm.overcommit_memory 解釋 一、概念與作用 vm.overcommit_memory 是 Linux 內核中的一個參數&#xff0c;用于控制內存分配的“過度承諾”&#xf…

Python:.py文件轉換為雙擊可執行的Windows程序(版本2)

流程步驟&#xff1a; 這個流程圖展示了將 Python .py 文件轉換為 Windows 可執行程序的完整過程&#xff0c;主要包括以下步驟&#xff1a; 1、準備 Python文件&#xff0c;確保代碼可獨立運行 2、安裝打包工具&#xff08;如 PyInstaller&#xff09; 3、打開命令提示符并定位…

【請關注】mysql一些經常用到的高級SQL

經常去重復數據&#xff0c;數據需要轉等操作&#xff0c;匯總高級SQL MySQL操作 一、數據去重&#xff08;Data Deduplication&#xff09; 去重常用于清除重復記錄&#xff0c;保留唯一數據。 1. 使用DISTINCT關鍵字去重單列 -- 從用戶表中獲取唯一的郵箱地址 SELECT DISTIN…

RA4M2開發涂鴉模塊CBU(2)----配置按鍵開啟LED

RA4M2開發涂鴉模塊CBU.2--配置按鍵開啟LED 概述視頻教學樣品申請硬件準備參考程序按鍵口配置中斷回調函數主程序 概述 本實驗演示如何在 Renesas RA4M2 單片機上使用 GPIO 輸入&#xff08;按鍵&#xff09; 觸發 GPIO 輸出&#xff08;LED&#xff09;&#xff0c;并使用e2st…

Linux——Json

一 概念 json是一種輕量級&#xff0c;基于文本的&#xff0c;可讀的數據交換格式&#xff0c;能夠讓數據在不同系統&#xff08;比如前端—后端&#xff0c;服務器—客戶端&#xff09;間方便傳遞/存儲。在編程語言中都內置了處理json數據的方法 二 語法規則 1. 數據格式&a…

大模型之微調篇——指令微調數據集準備

寫在前面 高質量數據的準備是微調大模型的重中之重&#xff0c;一些高質量的數據集可能遠比模型性能更佳重要。 我是根據自己的數據照著B站up code花園LLaMA Factory 微調教程&#xff1a;如何構建高質量數據集&#xff1f;_嗶哩嗶哩_bilibili做的。 數據集格式 在LLaMA Fa…

LVS—DR模式

LVS—DR模式 LVS DR 模式詳細簡介 一、模式定義與核心原理 LVS DR&#xff08;Direct Routing&#xff09;模式&#xff0c;即直接路由模式&#xff0c;是 Linux Virtual Server&#xff08;LVS&#xff09;實現負載均衡的經典模式之一&#xff0c;工作于網絡四層&#xff0…

寶玉分享VibeCoding構建Agent

借助 Claude Code 完成的一個翻譯智能體 (Translator Agent)。你只需輸入一段文字、一個網址或一個本地文件路徑&#xff0c;它就能自動提取內容并完成翻譯。更酷的是&#xff0c;它還能修正原文中的拼寫錯誤&#xff0c;確保譯文的準確流暢。 到底什么是“真正的”AI Agent&a…

在spring boot中使用Logback

在 Spring Boot 中使用 Logback 作為日志框架是開發中的常見需求&#xff0c;因其高性能和靈活配置而廣受青睞。以下是詳細實踐指南&#xff0c;結合了配置方法、代碼示例及最佳實踐&#xff1a; &#x1f527; 一、依賴配置 Spring Boot 默認集成了 Logback&#xff0c;無需手…

騰訊云 Lighthouse 輕量應用服務器:數據驅動的架構選型指南

摘要&#xff1a;騰訊云 Lighthouse 作為面向輕量級應用場景的優化解決方案&#xff0c;通過高性價比套餐式售賣、開箱即用應用模板及流量包計費模式&#xff0c;顯著降低中小企業與開發者的上云門檻。本文基于性能測試與橫向對比&#xff0c;量化分析其核心優勢與適用邊界。 …

Linux TCP/IP協議棧中的TCP輸入處理:net/ipv4/tcp_input.c解析

在網絡通信領域,TCP(傳輸控制協議)因其可靠的面向連接特性而被廣泛應用。Linux內核的TCP/IP協議棧實現了對TCP協議的高效處理,其中net/ipv4/tcp_input.c文件扮演著關鍵角色,負責處理TCP數據包的輸入邏輯。下面是對該文件核心功能的深入剖析。 一、TCP數據包接收與處理 (…

物聯網傳輸網關、RTU、DTU及SCADA系統技術解析

目錄 摘要 一、引言 二、物聯網傳輸網關 1. 定義 2. 類型 3. 分類 4. 工作原理 5. 差異分析 總結&#xff1a; 三、RTU&#xff08;遠程終端單元&#xff09; 1. 定義 2. 工作原理 3. 特點 4. 應用場景 四、DTU&#xff08;數據傳輸單元&#xff09; 1. 定義 …

【unity游戲開發——熱更新】YooAsset簡化資源加載、打包、更新等流程

注意&#xff1a;考慮到熱更新的內容比較多&#xff0c;我將熱更新的內容分開&#xff0c;并全部整合放在【unity游戲開發——熱更新】專欄里&#xff0c;感興趣的小伙伴可以前往逐一查看學習。 文章目錄 前言1、什么是YooAsset&#xff1f;2、系統需求3、系統特點 一、下載安裝…