【C++設計模式之Observer觀察者模式】

Observer觀察者模式

  • 模式定義
  • 動機(Motivation)
  • 結構(Structure)
  • 應用場景一(氣象站)實現步驟
    • 1.定義觀察者接口
    • 2.定義被觀察者(主題)接口
    • 3.實現具體被觀察者對象(氣象站)
    • 4.實現具體觀察者(例如:顯示屏)
    • 5.main.cpp中使用示例
    • 6.輸出結果
    • 7. 關鍵點
  • 應用場景二(溫度傳感器)實現步驟
    • 1.定義觀察者接口
    • 2.定義被觀察者接口
    • 3.實現具體被觀察者(溫度傳感器)
    • 4.實現具體觀察者(溫度顯示屏)
    • 5.使用示例
  • 要點總結


模式定義

觀察者模式:定義對象間的一種一對多(變化)的依賴關系,以便當一個對象(Subject)的狀態發生改變時,所有依賴于它的對象都得到通知并自動更新。

允許對象(觀察者)訂閱另一個對象(被觀察者)的狀態變化,并在狀態變化時自動接收通知。

動機(Motivation)

  • 在軟件構建過程中,我們需要為某些對象建立一種“通知依賴關系”——一個對象(目標對象)的狀態發送改變,所有的依賴對象(觀察者對象)都將得到通知。如果這樣的依賴關系過于密切,將使軟件不能很好地抵御變化。
  • 使用面向對象技術,可以將這種依賴關系弱化,并形成一種穩定的依賴關系。從而實現軟件體系結構的松耦合。

結構(Structure)

在這里插入圖片描述

應用場景一(氣象站)實現步驟

1.定義觀察者接口

observer.h頭文件

#pragma once
#include<vector>
#include<algorithm>//觀察者接口
class Observer {
public:virtual ~Observer() = default;virtual void update() = 0;     //更新方法(純虛函數)
};

2.定義被觀察者(主題)接口

subject.h頭文件

#pragma once
#include "observer.h"class Subject {
public:virtual ~Subject() = default;virtual void attach(Observer*observer) = 0;   //注冊觀察者virtual void detach(Observer*observer) = 0;   //移除觀察者virtual void notify() = 0;                    //通知觀察者protected:std::vector<Observer*> observers_;             //存儲觀察則列表
};

3.實現具體被觀察者對象(氣象站)

concretesubject.h

#pragma once
#include"subject.h"class WeatherStation :public Subject {
public://注冊觀察者void attach(Observer* observer)override {observers_.push_back(observer);}//移除觀察者void detach(Observer*observer)override {auto it = std::remove(observers_.begin(), observers_.end(), observer);observers_.erase(it, observers_.end());}//通知所有觀察者void notify()override {for (auto observer : observers_) {observer->update();}}//更新氣象數據并觸發通知void setMeasurements(float temperature, float humidity) {temperature_ = temperature;humidity_ = humidity;notify();    //數據變化時通知觀察者}//獲取數據(供觀察者拉取)float getTemperature()const { return temperature_; }float getHumidity()const { return humidity_; }private:float temperature_ = 0.0f;float humidity_ = 0.0f;
};

4.實現具體觀察者(例如:顯示屏)

concreteobserver.h

#pragma once
#include<iostream>
#include"observer.h"
#include"concretesubject.h"
class Display :public Observer {
public:explicit Display(WeatherStation&station):station_(station){}//當被觀察者通知時,更新顯示void update()override {std::cout << "Temperature: " << station_.getTemperature()<< " ℃,Humidity : " << station_.getHumidity() << "% \n";}
private:WeatherStation& station_;
};

5.main.cpp中使用示例

#include <iostream>
#include"concretesubject.h"
#include"concreteobserver.h"int main()
{WeatherStation station;  // 被觀察者(氣象站)Display display1(station);  // 觀察者1(顯示屏)Display display2(station);  // 觀察者2// 注冊觀察者station.attach(&display1);station.attach(&display2);// 更新數據,自動觸發觀察者更新station.setMeasurements(25.5f, 60.0f);station.setMeasurements(26.0f, 55.0f);// 移除一個觀察者station.detach(&display2);station.setMeasurements(27.0f, 50.0f);return 0;
}

6.輸出結果

Temperature: 25.5 ℃,Humidity : 60%
Temperature: 25.5 ℃,Humidity : 60%
Temperature: 26 ℃,Humidity : 55%
Temperature: 26 ℃,Humidity : 55%
Temperature: 27 ℃,Humidity : 50%

7. 關鍵點

  • 松耦合:觀察者和被觀察者通過接口交互,無需知道彼此的具體實現。

  • 推拉模型

    • 推模式:被觀察者將數據直接推送給觀察者(通過 update 方法參數)。

    • 拉模式:觀察者主動從被觀察者拉取數據(本例中使用 getTemperature() 和 getHumidity())。

  • 內存管理:需確保觀察者的生命周期覆蓋被觀察者,或使用 shared_ptr 管理資源。

應用場景二(溫度傳感器)實現步驟

1.定義觀察者接口

observer.h

#pragma once
//定義觀察者接口
class Observer {
public:virtual ~Observer() = default;virtual void update() = 0;    //更新方法
};

2.定義被觀察者接口

subject.h

#pragma once
#include"observer.h"
#include<vector>
class Subject {
public:virtual ~Subject() = default;virtual void attach(Observer*observer) = 0;  //注冊觀察者virtual void detach(Observer*observer) = 0;  //移除觀察者virtual void notify() = 0;                   //通知觀察者
protected:std::vector<Observer*>observers_;
};

3.實現具體被觀察者(溫度傳感器)

concretesubject.h

#pragma once
#include"subject.h"
#include <algorithm>class TemperatureSensor :public Subject {
public:void attach(Observer*observer)override {observers_.push_back(observer);}void detach(Observer* observer) override {auto it = std::remove(observers_.begin(), observers_.end(), observer);observers_.erase(it, observers_.end());}void notify() override {for (auto observer : observers_) {observer->update();}}void setTemperature(float temp) {temperature_ = temp;notify();  // 溫度變化時通知所有觀察者}float getTemperature() const { return temperature_; }private:float temperature_ = 0.0f;
};

4.實現具體觀察者(溫度顯示屏)

concreteobserver.h

#pragma once
#include"observer.h"
#include "concretesubject.h"
#include<iostream>class TemperatureDisplay :public Observer {
public:explicit TemperatureDisplay(TemperatureSensor&sensor):sensor_(sensor){}void update()override {std::cout << "當前溫度: " << sensor_.getTemperature() << " ℃\n";}
private:TemperatureSensor& sensor_;
};

5.使用示例

#include"concreteobserver.h"
#include"concretesubject.h"int main() {TemperatureSensor sensor;TemperatureDisplay display(sensor);sensor.attach(&display);sensor.setTemperature(25.5f);  // 輸出:當前溫度: 25.5°Csensor.detach(&display);sensor.setTemperature(26.0f);  // 無輸出return 0;
}

要點總結

  • 使用面向對象的抽象,Observer模式使得我們可以獨立地改變目標與觀察者,從而使二者之間的依賴關系達致松耦合。
  • 目標發送通知時,無需指定觀察者,通知(可以攜帶通知信息作為參數)會自動傳播。
  • 觀察者自己決定是否需要訂閱通知,目標對象對此一無所知。
  • Observer模式是基于事件的UI框架中非常常用的設計模式,也是MVC模式的一個重要組成部分。

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

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

相關文章

資產月報怎么填?資產月報填報指南

資產月報是企業對固定資產進行定期檢查和管理的重要工具&#xff0c;它能夠幫助管理者了解資產的使用情況、維護狀況和財務狀況&#xff0c;從而為資產的優化配置和決策提供依據。填寫資產月報時&#xff0c;除了填報內容外&#xff0c;還需要注意格式的規范性和數據的準確性。…

UG471 之 SelectIO 邏輯資源

背景 《ug471》介紹了Xilinx 7 系列 SelectIO 的輸入/輸出特性及邏輯資源的相關內容。 第 1 章《SelectIO Resources》介紹了輸出驅動器和輸入接收器的電氣特性&#xff0c;并通過大量實例解析了各類標準接口的實現。 第 2 章《SelectIO Logic Resources》介紹了輸入輸出數據…

C++ 內存泄漏相關

ASAN 參考鏈接 https://blog.csdn.net/wonengguwozai/article/details/129593186https://www.cnblogs.com/greatsql/p/16256926.htmlhttps://zhuanlan.zhihu.com/p/700505587小demo // leak.c #include <stdio.h> #include <stdlib.h> #include <string.h>…

計算人聲錄音后電平的大小(dB SPL->dBFS)

計算人聲錄音后電平的大小 這里筆記記錄一下&#xff0c;怎么計算已知大小的聲音&#xff0c;經過麥克風、聲卡錄制后軟件內錄得的音量電平值。&#xff08;文章最后將計算過程整理為Python代碼&#xff0c;方便復用&#xff09; 假設用正常說話的聲音大小65dB&#xff08;SP…

【MySQL數據庫】C/C++連接數據庫

MySQL要想在C/C下使用&#xff0c;就必須要有 MySQL 提供的頭文件和相關的庫。 在Ubuntu系統上&#xff0c;使用 apt install mysql-server 安裝MySQL服務器后&#xff0c;僅安裝了MySQL數據庫服務本身&#xff0c;并沒有安裝MySQL開發所需的庫和頭文件。因此&#xff0c;在嘗試…

Kubernetes調度策略深度解析:NodeSelector與NodeAffinity的正確打開方式

在Kubernetes集群管理中&#xff0c;如何精準控制Pod的落點&#xff1f;本文將深入解析兩大核心調度策略的差異&#xff0c;并通過生產案例教你做出正確選擇。 一、基礎概念快速理解 1.1 NodeSelector&#xff08;節點選擇器&#xff09; 核心機制&#xff1a;通過標簽硬匹配…

Golang的linux運行環境的安裝與配置

很多新手在學go時&#xff0c;linux下的配置環境一頭霧水&#xff0c;總結下&#xff0c;可供參考&#xff01; --------------------------------------Golang的運行環境的安裝與配置-------------------------------------- 將壓縮包放在/home/tools/下 解壓 tar -zxvf g…

自定義實現elementui的錨點

背景 前不久有個需求&#xff0c;上半部分是el-step步驟條&#xff0c;下半部分是一些文字說明&#xff0c;需要實現點擊步驟條中某個步驟自定義定位到對應部分的文字說明&#xff0c;同時滾動內容區域的時候還要自動選中對應區域的步驟。element-ui-plus的有錨點這個組件&…

Oracle Fusion常用表

模塊表名表描述字段說明sodoo_headers_all銷售訂單頭表sodoo_lines_all銷售訂單行表sodoo_fulfill_lines_all銷售訂單明細行表popo_headers_all采購訂單頭表popo_lines_all采購訂單行表popo_line_locations_all采購訂單分配表popo_distributions_all采購訂單發運表invEGP_SYSTE…

面試常問系列(一)-神經網絡參數初始化-之-softmax

背景 本文內容還是對之前關于面試題transformer的一個延伸&#xff0c;詳細講解一下softmax 面試常問系列(二)-神經網絡參數初始化之自注意力機制-CSDN博客 Softmax函數的梯度特性與輸入值的幅度密切相關&#xff0c;這是Transformer中自注意力機制需要縮放點積結果的關鍵原…

5.9-selcct_poll_epoll 和 reactor 的模擬實現

5.9-select_poll_epoll 本文演示 select 等 io 多路復用函數的應用方法&#xff0c;函數具體介紹可以參考我過去寫的博客。 先綁定監聽的文件描述符 int sockfd socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in serveraddr; memset(&serveraddr, 0, sizeof(struc…

Python基礎語法(上)

常量和表達式 我們可以使用python來進行一些 - * / %的一些運算 print(1 2 - 3) print(1 2 * 3) print(1 2 / 3) python中的運算規則與數學當中一致&#xff0c;先乘除后加減&#xff0c;有括號的先計算括號里面的。 形如 1 2 - 3 這樣是算式, 在編程語言中稱為 表達式,…

數圖閃耀2025深圳CCFA中國零售博覽會:AI+零售數字化解決方案引發現場熱潮

展會時間&#xff1a;2025年5月8日—10日 地點&#xff1a;深圳國際會展中心&#xff08;寶安新館&#xff09; 【深圳訊】5月8日&#xff0c;亞洲規模最大的零售行業盛會——2025 CCFA中國零售博覽會在深圳盛大開幕。本屆展會匯聚全球25個國家和地區的900余家參展商&#xff…

方法:批量識別圖片區域文字并重命名,批量識別指定區域內容改名,基于QT和阿里云的實現方案,詳細方法

基于QT和阿里云的圖片區域文字識別與批量重命名方案 項目場景 ??企業檔案管理??:批量處理掃描合同、發票等文檔,根據編號或關鍵信息自動重命名文件??醫療影像管理??:識別X光、CT等醫學影像中的患者信息,按姓名+檢查日期重命名??電商訂單處理??:從訂單截圖中提…

Mybatis解決以某個字段存在,批量更新,不存在批量插入(高效)(一)

背景 在開發企業級應用時&#xff0c;我們經常需要處理批量數據的插入和更新操作。傳統的逐條處理方式性能低下&#xff0c;而簡單的REPLACE INTO或INSERT ... ON DUPLICATE KEY UPDATE在某些場景下又不夠靈活。本文將介紹一種基于臨時表的高效批量插入/更新方案&#xff0c;解…

JVM、JRE、JDK的區別

JVM JVM全稱Java虛擬機(Java Virtual Machine, JVM),它是運行java字節碼的虛擬機&#xff0c;JVM針對不同的系統有不同的實現&#xff0c;目的運行相同的字節碼有同樣的結果&#xff0c;JVM是“一次編譯&#xff0c;到處運行”實現的關鍵。如下不同的編程語言編譯生成字節碼文…

神經元和神經網絡定義

在深度學習中&#xff0c;神經元和神經網絡是構成神經網絡模型的基本元素。讓我們從基礎開始&#xff0c;逐步解釋它們的含義和作用。 1?? 神經元是什么&#xff1f; 神經元是神經網絡中的基本計算單元&#xff0c;靈感來自于生物神經系統中的神經元。每個人的腦中有數以億…

CDGP重點知識梳理

寫在前面 全文11700字,共82個重點知識 目 錄 考點分布 考試要求 第一章 數據管理-5%

Ubuntu 22.04 安裝配置遠程桌面環境指南

在云服務器或遠程主機上安裝圖形化桌面環境,可以極大地提升管理效率和用戶體驗。本文將詳細介紹如何在 Ubuntu 22.04 (Jammy Jellyfish) 系統上安裝和配置 Xfce4 桌面環境,并通過 VNC 實現遠程訪問。 系統環境 操作系統:Ubuntu 22.04 LTS (Jammy Jellyfish)架構:AMD64安裝…

node提示node:events:495 throw er解決方法

前言 之前開發的時候喜歡使用高版本&#xff0c;追求新的東西&#xff0c;然后回頭運行一下之前的項目提示如下 項目技術棧&#xff1a;node egg 報錯 node:events:495 throw er; // Unhandled error event ^ Error: ENOENT: no such file or directory, scandir F:\my\gi…