設計模式——觀察者設計模式(行為型)

摘要

本文詳細介紹了觀察者設計模式,包括其定義、結構、實現方式、適用場景以及實戰示例。通過代碼示例展示了如何在Spring框架下實現觀察者模式,以及如何通過該模式實現狀態變化通知。同時,對比了觀察者模式與消息中間件在設計理念、耦合程度、通信方式和分布式支持等方面的差異,幫助讀者更好地理解和選擇合適的實現方式。

1. 觀察者設計模式定義

觀察者設計模式(Observer Pattern)是一種行為型設計模式,定義了一種一對多的依賴關系,使得當一個對象(被觀察者)的狀態發生改變時,所有依賴它的對象(觀察者)都會得到自動通知并更新,從而實現對象間的松耦合和實時通訊。觀察者模式通過定義對象間的發布-訂閱關系,實現事件的自動通知和響應,適合事件驅動和異步消息場景。

1.1. 核心定義

角色

  • 被觀察者(Subject):維護一組觀察者,負責狀態的管理和通知。
  • 觀察者(Observer):注冊到被觀察者,一旦被觀察者狀態變化,接收通知并執行相應動作。

目的:讓多個觀察者對象自動獲得被觀察者的狀態變化,降低對象間耦合度。

2. 觀察者設計模式結構

觀察者模式包含如下角色:

  • Subject: 目標
  • ConcreteSubject: 具體目標
  • Observer: 觀察者
  • ConcreteObserver: 具體觀察者

2.1. 觀察者模式類圖

2.2. 觀察者模式時序圖

3. 觀察者設計模式實現方式

3.1. 觀察者設計模式實現步驟

3.1.1. 定義抽象主題(Subject)接口

  • 提供注冊、移除和通知觀察者的方法。
public interface Subject {void registerObserver(Observer observer);void removeObserver(Observer observer);void notifyObservers();
}

3.1.2. 定義抽象觀察者(Observer)接口

  • 聲明一個更新方法,主題狀態變化時調用。
public interface Observer {void update(String message);
}

3.1.3. 具體主題類實現 Subject

  • 維護觀察者列表,實現注冊、移除、通知邏輯。
  • 當自身狀態變化時調用 notifyObservers(),遍歷通知所有觀察者。
import java.util.ArrayList;
import java.util.List;public class ConcreteSubject implements Subject {private final List<Observer> observers = new ArrayList<>();private String state;@Overridepublic void registerObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(state);}}public void setState(String state) {this.state = state;notifyObservers();}
}

3.1.4. 具體觀察者實現 Observer

  • 實現 update 方法,接收通知并做出響應。
public class ConcreteObserver implements Observer {private String name;public ConcreteObserver(String name) {this.name = name;}@Overridepublic void update(String message) {System.out.println(name + " 收到通知,狀態變為: " + message);}
}

3.2. 觀察者測試示例

public class ObserverPatternDemo {public static void main(String[] args) {ConcreteSubject subject = new ConcreteSubject();Observer observer1 = new ConcreteObserver("觀察者1");Observer observer2 = new ConcreteObserver("觀察者2");subject.registerObserver(observer1);subject.registerObserver(observer2);subject.setState("狀態1");subject.setState("狀態2");}
}

說明

  • 主題(Subject)維護觀察者集合,狀態變化時通知所有觀察者。
  • 觀察者實現更新接口,獲得主題最新狀態。

4. 觀察者設計模式適合場景

4.1. ? 適合使用觀察者設計模式的場景

適合場景

說明

事件驅動系統

事件產生后需要通知多個模塊或對象做出響應,如 UI 事件監聽、消息推送。

一對多依賴關系

一個對象狀態變化需要通知多個依賴對象,如股票價格更新通知所有訂閱者。

松耦合需求

希望對象間解耦,觀察者與被觀察者不直接依賴,實現靈活擴展。

廣播通信

需要將消息廣播給多個接收者,且接收者可動態增加和移除。

異步通知

狀態更新后,通知觀察者進行異步處理。

分布式系統

多個服務或模塊之間的狀態同步與消息推送。

4.2. ? 不適合使用觀察者設計模式的場景

不適合場景

說明

對象之間不存在依賴關系

彼此獨立的對象無需相互通知。

通知對象數量固定且簡單

只有少數固定對象,且耦合關系明確,使用簡單調用即可。

需要嚴格同步控制的場景

觀察者通知是異步的,無法滿足嚴格同步時序需求。

性能敏感場景

大量觀察者通知導致性能開銷大,影響系統響應速度。

過度使用導致復雜性增加

觀察者鏈條過長,維護困難,代碼難以理解。

總結:觀察者模式主要適用于需要“自動廣播狀態變化給多個對象”且“希望對象間低耦合”的場景。不適合簡單調用、同步嚴格或性能瓶頸明顯的場景。

5. 觀察者設計模式實戰示例

5.1. 場景說明

在風控系統中,當訂單狀態發生變化(比如風控審核結果出來后),需要通知多個模塊(比如日志記錄模塊、報警模塊、緩存更新模塊)來響應該狀態變化。

5.2. 定義觀察者接口

public interface OrderStatusObserver {void update(String orderId, String status);
}

5.3. 定義具體觀察者實現類

import org.springframework.stereotype.Component;@Component
public class LoggingObserver implements OrderStatusObserver {@Overridepublic void update(String orderId, String status) {System.out.println("日志模塊:訂單 " + orderId + " 狀態更新為:" + status);// 這里可以寫日志持久化操作}
}@Component
public class AlertObserver implements OrderStatusObserver {@Overridepublic void update(String orderId, String status) {if ("REJECTED".equals(status)) {System.out.println("報警模塊:訂單 " + orderId + " 審核拒絕,觸發報警!");// 觸發報警邏輯}}
}@Component
public class CacheObserver implements OrderStatusObserver {@Overridepublic void update(String orderId, String status) {System.out.println("緩存模塊:更新訂單 " + orderId + " 狀態緩存為:" + status);// 緩存刷新邏輯}
}

5.4. 定義主題接口和實現類

public interface OrderStatusSubject {void registerObserver(OrderStatusObserver observer);void removeObserver(OrderStatusObserver observer);void notifyObservers(String orderId, String status);
}
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;@Component
public class OrderStatusSubjectImpl implements OrderStatusSubject {private final List<OrderStatusObserver> observers = new ArrayList<>();// 使用Spring自動注入所有實現了OrderStatusObserver接口的Bean@Autowiredprivate List<OrderStatusObserver> observerBeans;@PostConstructpublic void init() {// 初始化時,將所有觀察者注冊進列表observers.addAll(observerBeans);}@Overridepublic void registerObserver(OrderStatusObserver observer) {observers.add(observer);}@Overridepublic void removeObserver(OrderStatusObserver observer) {observers.remove(observer);}@Overridepublic void notifyObservers(String orderId, String status) {for (OrderStatusObserver observer : observers) {observer.update(orderId, status);}}
}

5.5. 4. 業務調用示例(比如風控服務)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class RiskControlService {@Autowiredprivate OrderStatusSubject orderStatusSubject;public void auditOrder(String orderId, boolean passed) {// 風控業務邏輯String status = passed ? "APPROVED" : "REJECTED";System.out.println("風控審核完成,訂單:" + orderId + ",狀態:" + status);// 審核完成后,通知所有觀察者orderStatusSubject.notifyObservers(orderId, status);}
}

5.6. 測試Controller(可選)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class RiskController {@Autowiredprivate RiskControlService riskControlService;@PostMapping("/auditOrder")public String auditOrder(@RequestParam String orderId, @RequestParam boolean passed) {riskControlService.auditOrder(orderId, passed);return "審核完成";}
}

5.7. 實戰示例總結

  • 觀察者接口 OrderStatusObserver,多個實現類由Spring管理并注入。
  • 主題 OrderStatusSubjectImpl 維護觀察者列表,利用 @Autowired 自動注入所有觀察者Bean。
  • 風控業務執行后調用主題的 notifyObservers(),實現狀態變化通知。
  • 全部采用Spring注解管理,未用構造函數注入,代碼簡潔且易于擴展。

6. 觀察者設計模式思考

6.1. 觀察著模式和使用消息中間件來通知處理的方式有什么不同?

很好的問題!觀察者模式和消息中間件在實現“發布-訂閱”或通知機制時都很常用,但它們的設計理念、實現方式和適用場景有顯著差別。下面幫你詳細分析兩者的區別:

維度

觀察者模式

消息中間件(如Kafka、RabbitMQ、ActiveMQ等)

設計層次

設計模式,屬于應用內部的設計范式,通常是在代碼內部直接實現。

獨立的中間件系統,屬于基礎設施層,提供異步消息傳遞機制。

耦合程度

被觀察者和觀察者耦合較緊密,觀察者必須知道被觀察者實例(盡管解耦設計可以降低耦合)。

發布者和訂閱者完全解耦,彼此不直接依賴,只通過消息中間件通信。

通信方式

通常是同步調用,狀態變化時立即調用觀察者的更新方法。

典型異步通信,消息發送后,接收方異步消費,支持異步處理和緩沖。

分布式支持

一般用于單體應用或同一JVM內對象之間的通知。

天生支持分布式系統,跨進程、跨服務器,甚至跨數據中心的消息傳遞。

擴展性

觀察者數量有限,擴展時需要修改代碼或依賴注入配置。

高度擴展,支持大量消費者和復雜路由規則,方便動態添加消費者。

容錯與持久化

無持久化和容錯機制,一旦通知失敗可能丟失信息。

支持消息持久化、重試、消息確認、死信隊列,增強系統可靠性。

性能影響

觀察者調用是同步的,影響調用鏈的執行時間,可能導致性能瓶頸。

異步處理,解耦主業務流程,提升系統吞吐量和響應速度。

使用場景

小型系統、UI事件響應、簡單狀態同步、模塊內部事件通知。

大型分布式系統、微服務間異步通信、異步任務調度、事件驅動架構。

6.1.1. 簡單總結:

  • 觀察者模式 適合應用內、輕量級的同步通知,設計簡單,適合對象之間狀態變化通知。
  • 消息中間件 適合跨進程、跨網絡、異步且高可靠的消息通信,適合分布式系統異步解耦和復雜事件流轉。

6.1.2. 舉例對比:

  • 觀察者模式:風控模塊風控結果出來后,同步通知日志模塊和報警模塊,立即處理。
  • 消息中間件:風控模塊發布“風控結果”消息到消息隊列,日志模塊和報警模塊異步訂閱該消息,消息隊列保證消息可靠送達和解耦。

博文參考

  • 3. 觀察者模式 — Graphic Design Patterns
  • 觀察者設計模式

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

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

相關文章

uniapp 頁面棧一定深度后,回首頁導航到新頁面的解決方案

uniapp 頁面棧一定深度后&#xff0c;回首頁導航到新頁面的解決方案 uniapp 頁面導航解決方案 在 uniapp 中&#xff0c;要實現先彈出頁面棧回到首頁&#xff0c;然后再跳轉到指定頁面。 /*** description 后臺選擇鏈接專用跳轉*/ interface Link {path: string;name?: stri…

數據結構 散列表 學習 2025年6月12日15:30:48

數據結構 散列表 哈希表(Hash Table): 通過哈希函數將鍵&#xff08;key&#xff09;映射到存儲位置&#xff0c;從而實現快速的插入、刪除和查找操作。 哈希表是現代編程中最重要的數據結構之一&#xff0c;幾乎所有編程語言都提供了內置實現。 計數 #include <stdio.h&g…

數據結構之LinkedList

系列文章目錄 數據結構之ArrayList-CSDN博客 目錄 系列文章目錄 前言 一、模擬實現鏈表 1. 遍歷鏈表 2. 插入節點 3. 刪除節點 4. 清空鏈表 二、鏈表的常見操作 1. 反轉鏈表 2. 返回鏈表的中間節點 3. 鏈表倒數第 k 個節點 4. 合并兩個有序鏈表 5. 分割鏈表 6. 判…

DC3靶機滲透

1. 靶機介紹 主要的內容有 sql 注入漏洞、joomla 框架漏洞、ssh 攻擊、shell 反彈、提權 信息收集(ip、端口、目錄、指紋信息)--->利用漏洞--->反彈---->提權 2. 信息收集 2.1. 掃描存活 ip 192.168.220.134 2.2. 端口掃描 nmap -T4 -A -p- 192.168.220.134 …

C# 線程交互

一、為什么要進行線程交互 在C#中&#xff0c;線程交互通常涉及到多個線程之間的數據共享和同步。?. 一、全局變量 在C#中&#xff0c;全局變量是指在程序的任何地方都可以訪問的變量。通常&#xff0c;全局變量是在類的外部定義的&#xff0c;或者在所有方法之外定義的。全…

Cursor 編輯器中的 Notepad 功能使用指南

Cursor 編輯器中的 Notepad 功能使用指南 摘要 本指南全面介紹了 Cursor 編輯器中的 Notepad 功能&#xff0c;涵蓋其用途、多種訪問方式、適用場景以及與其它功能的整合技巧等內容&#xff0c;助力用戶高效利用該功能提升工作流程效率。 不同訪問方式介紹 功能概述 Curso…

用于評估大語言模型(LLMs)能力的重要基準任務(Benchmark)

基準任務涵蓋了 多領域&#xff08;如語言理解、數學、推理、編程、醫學等&#xff09;和 多能力維度&#xff08;如事實檢索、計算、代碼生成、鏈式推理、多語言處理&#xff09;。常用于模型發布時的對比評測&#xff0c;例如 GPT-4、Claude、Gemini、Mistral 等模型的論文或…

力扣HOT100之技巧:169. 多數元素

這道題如果不考慮空間復雜度和時間復雜度的限制的話很好做&#xff0c;一種思路是通過一次遍歷將所有元素的數量記錄在一個哈希表中&#xff0c;然后我們直接返回出現次數最多的鍵即可。另一種思路是直接對數組進行排序&#xff0c;數組中間的值一定是多數元素&#xff0c;因為…

wordpress首頁調用指定ID頁面內的相冊

要在WordPress首頁調用ID為2的頁面中的相冊&#xff0c;你可以使用以下幾種方法&#xff1a; 方法一&#xff1a;使用短代碼和自定義查詢 首先&#xff0c;在你的主題的functions.php文件中添加以下代碼&#xff1a; function display_page_gallery($atts) {$atts shortcod…

基于深度學習的異常檢測系統:原理、實現與應用

前言 在現代數據驅動的業務環境中&#xff0c;異常檢測&#xff08;Anomaly Detection&#xff09;是一個關鍵任務&#xff0c;它能夠幫助企業和組織及時發現數據中的異常行為或事件&#xff0c;從而采取相應的措施。異常檢測廣泛應用于金融欺詐檢測、網絡安全、工業設備故障監…

Java基于BS架構的OA流程可視化實戰:從工作流引擎到前端交互(附完整源代碼+論文框架)

一、引言&#xff1a;BS架構OA系統的流程可視化需求 在企業信息化建設中&#xff0c;基于瀏覽器/服務器&#xff08;BS&#xff09;架構的OA系統通過流程自動化提升辦公效率&#xff0c;而流程可視化是實現流程監控、優化的核心模塊。本文基于Java技術棧&#xff0c;結合Activ…

JavaWeb-數據庫連接池

目錄 1.springboot默認Hikari(追光者)連接池 2.切換為Druid(德魯伊)連接池 1.springboot默認Hikari(追光者)連接池 2.切換為Druid(德魯伊)連接池 一般幾乎用不到&#xff0c;不需要切換 <!--Druid連接池--> <dependency><groupId>com.alibaba</groupId&…

c# 完成恩尼格瑪加密擴展

c# 完成恩尼格瑪加密擴展 恩尼格瑪擴展為可見字符恩尼格瑪的設備原始字符順序轉子的設置反射器的設置連接板的設置 初始數據的設置第一版 C# 代碼第二版 C# 代碼 總結 恩尼格瑪 在之前&#xff0c;我們使用 python 實現了一版恩尼格瑪的加密算法&#xff0c;但是這一版&#x…

【Redisson】鎖可重入原理

目錄 一、基本原理 二、源碼解析&#xff1a; &#xff08;2&#xff09;獲取鎖 &#xff08;1&#xff09;釋放鎖&#xff1a; 之前給大家介紹過redisson的分布式鎖&#xff0c;用redisson來實現比自己手搓簡單的分布式鎖有很多好處&#xff0c;因為這些可重入、可重試的邏…

BERT 模型微調與傳統機器學習的對比

BERT 微調與傳統機器學習的區別和聯系&#xff1a; 傳統機器學習流程 傳統機器學習處理文本分類通常包含以下步驟&#xff1a; 特征工程&#xff1a;手動設計特征&#xff08;如 TF-IDF、詞袋模型&#xff09;模型訓練&#xff1a;使用分類器&#xff08;如 SVM、隨機森林、邏…

(12)-Fiddler抓包-Fiddler設置IOS手機抓包

1.簡介 Fiddler不但能截獲各種瀏覽器發出的 HTTP 請求&#xff0c;也可以截獲各種智能手機發出的HTTP/ HTTPS 請求。 Fiddler 能捕獲Android 和 Windows Phone 等設備發出的 HTTP/HTTPS 請求。同理也可以截獲iOS設備發出的請求&#xff0c;比如 iPhone、iPad 和 MacBook 等蘋…

芯科科技Tech Talks技術培訓重磅回歸:賦能物聯網創新,共筑智能互聯未來

聚焦于Matter、藍牙、Wi-Fi、LPWAN、AI/ML五大熱門無線協議與技術 為年度盛會Works With大會賦能先行 隨著物聯網&#xff08;IoT&#xff09;和人工智能&#xff08;AI&#xff09;技術的飛速發展&#xff0c;越來越多的企業和個人開發者都非常關注最新的無線連接技術和應用…

docker-compose容器單機編排

docker-compose容器單機編排 開篇前言 隨著網站架構的升級&#xff0c;容器的使用也越來越頻繁&#xff0c;應用服務和容器之間的關系也越發的復雜。 這個就要求研發人員能更好的方法去管理數量較多的服務器&#xff0c;而不能手動挨個管理。 例如一個LNMP 架構&#xff0c;就…

LeetCode--29.兩數相除

解題思路&#xff1a; 1.獲取信息&#xff1a; 給定兩個整數&#xff0c;一個除數&#xff0c;一個被除數&#xff0c;要求返回商&#xff08;商取整數&#xff09; 限制條件&#xff1a;&#xff08;1&#xff09;不能使用乘法&#xff0c;除法和取余運算 &#xff08;2&#…

中山大學GaussianFusion:首個將高斯表示引入端到端自動駕駛多傳感器融合的新框架

摘要 近年來由于端到端自動駕駛極大簡化了原有傳統自動駕駛模塊化的流程&#xff0c;吸引了來自工業界和學術界的廣泛關注。然而&#xff0c;現有的端到端智駕算法通常采用單一傳感器&#xff0c;使其在處理復雜多樣和具有挑戰性的駕駛場景中受到了限制。而多傳感器融合可以很…