設計模式:觀察者模式 (Observer) 案例詳解

目錄

一、引言:為什么需要觀察者模式?

二、觀察者模式的核心原理

1. 角色劃分

2. 類圖關系

三、經典案例解析

案例1:天氣監測系統

案例2:股票價格監控系統

案例3:MVC架構中的模型-視圖分離

案例4:Java內置事件監聽機制

四、進階技巧與注意事項

1. 避免循環依賴

2. 異步通知

3. Java內置支持

五、對比其他設計模式

六、總結與建議


一、引言:為什么需要觀察者模式?

在軟件開發中,對象之間的耦合度越高,代碼的維護性和擴展性越差。例如:

  • 事件處理:當一個對象的狀態變化需要通知多個其他對象時(如GUI按鈕點擊觸發多個事件)。
  • 數據同步:當數據源更新時,多個依賴該數據的對象需要自動刷新(如股票價格變動通知投資者)。
    傳統方案中,對象間直接調用會導致強耦合,而觀察者模式通過解耦解決了這一問題。

二、觀察者模式的核心原理

1. 角色劃分
  • Subject(主題):維護觀察者列表,提供注冊、移除和通知觀察者的接口。
  • Observer(觀察者):定義更新接口,接收主題的通知并自動更新。
  • ConcreteSubject(具體主題):實現主題接口,管理觀察者列表,狀態變化時通知觀察者。
  • ConcreteObserver(具體觀察者):實現觀察者接口,定義收到通知后的具體行為。
2. 類圖關系
[Subject] <-- [ConcreteSubject]▼List<Observer>▲
[Observer] --> [ConcreteObserver]

三、經典案例解析

案例1:天氣監測系統

背景:氣象站實時采集溫度、濕度數據,多個顯示設備(如當前狀況、統計圖表)需同步更新。

實現步驟

  1. 定義主題接口
    interface Subject {void registerObserver(Observer o);void removeObserver(Observer o);void notifyObservers();
    }
    
  2. 實現具體主題
    class WeatherData implements Subject {private List<Observer> observers;private float temperature;public void setMeasurements(float temp, float hum) {this.temperature = temp;notifyObservers();}public void notifyObservers() {for (Observer observer : observers) {observer.update(temperature);}}// 注冊、移除觀察者方法省略
    }
    
  3. 定義觀察者接口
    interface Observer {void update(float temperature);
    }
    
  4. 實現具體觀察者
    class CurrentConditionsDisplay implements Observer {public void update(float temperature) {System.out.println("當前溫度:" + temperature + "°C");}
    }
    

效果

  • 新增顯示設備(如統計圖表)只需實現Observer接口,無需修改WeatherData
  • 主題與觀察者解耦,支持動態擴展。
案例2:股票價格監控系統

背景:投資者訂閱股票信息,當價格變動時需實時通知所有訂閱者。

實現亮點

  • 主題Stock類維護價格和觀察者列表。
  • 觀察者Investor類實現更新邏輯,如觸發買入/賣出操作。
  • 動態訂閱:投資者可隨時添加或取消訂閱。

代碼片段

class Stock implements Subject {private List<Observer> investors = new ArrayList<>();private double price;public void setPrice(double newPrice) {this.price = newPrice;notifyObservers();}public void notifyObservers() {for (Observer investor : investors) {investor.update(price);}}
}
案例3:MVC架構中的模型-視圖分離

背景:模型層(Model)數據變化時,多個視圖層(如柱狀圖、餅圖)需自動更新。

實現邏輯

  • 模型:作為主題,存儲數據并通知視圖。
  • 視圖:作為觀察者,訂閱模型更新。
  • 優勢:視圖與模型解耦,支持任意數量的視圖擴展。

示例

class Model implements Subject {private int data;public void setData(int newData) {this.data = newData;notifyObservers();}
}
class BarChart implements Observer {public void update(int data) {System.out.println("柱狀圖更新:" + data);}
}
案例4:Java內置事件監聽機制

背景:GUI按鈕點擊事件需觸發多個操作(如彈窗、日志記錄)。

實現原理

  • 事件源:按鈕作為主題,觸發事件。
  • 事件監聽器:觀察者實現ActionListener接口,處理事件。

代碼示例

JButton button = new JButton("Click");
button.addActionListener(e -> System.out.println("按鈕被點擊!"));

四、進階技巧與注意事項

1. 避免循環依賴

若觀察者在update()中修改主題狀態,可能導致無限遞歸。解決方案:

  • 限制通知層級(如僅通知一次)。
  • 使用標志位判斷是否正在通知。
2. 異步通知

在復雜系統中,同步通知可能阻塞主線程。可通過異步回調消息隊列優化:

new Thread(() -> notifyObservers()).start();
3. Java內置支持

JDK提供java.util.Observablejava.util.Observer,但存在以下問題:

  • 觀察者與主題強綁定,難以擴展。
  • 建議自定義接口,提升靈活性。

五、對比其他設計模式

模式核心目標觀察者模式適用場景
策略模式算法替換需動態切換行為(如排序算法)
中介者模式多對象通信協調復雜對象網狀關系(如聊天室)
發布-訂閱事件分發(如消息隊列)高并發、異步事件處理

六、總結與建議

觀察者模式通過解耦廣播機制,完美解決對象間一對多依賴問題。在實際開發中:

  1. 優先解耦:將主題與觀察者職責分離,避免直接調用。
  2. 靈活擴展:通過接口定義,支持動態添加新觀察者。
  3. 謹慎處理循環依賴:設計時需考慮通知順序和條件。

實踐建議

  • 初學者從簡單案例(如天氣系統)入手,理解核心邏輯。
  • 在職開發者可研究開源框架(如RxJava、Spring事件機制)中的實現。

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

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

相關文章

CTF-Misc:開啟全方位解題之旅

目錄 一、CTF-Misc 入門指引二、基礎技能儲備2.1 文件格式識別2.2 基礎工具使用 三、信息搜集技巧3.1 搜索引擎技巧3.2 網絡信息挖掘 四、編碼轉換奧秘4.1 常見編碼類型4.2 編碼轉換工具 五、隱寫分析秘籍5.1 圖片隱寫5.1.1 LSB 隱寫5.1.2 顏色通道與 Exif 信息5.1.3 圖片修復與…

Adobe創意套件深度挖掘:效率倍增與靈感迸發的新玩法

最近在深入體驗奧地利Blueskyy藝術學院的Adobe正版教育訂閱&#xff0c;并研究全家桶時有不少新發現&#xff0c;忍不住想和大家分享一下。 先簡單說下這個訂閱的感受&#xff1a; Firefly 積分。 這應該是我用過Firefly積分最多的版本&#xff0c;1500點/周。對于我們這些創意…

左神算法之有序二維矩陣中的目標值查找

有序二維矩陣中的目標值查找 目錄 有序二維矩陣中的目標值查找1. 題目描述2. 問題解釋3. 解決思路方法一&#xff1a;逐行二分查找&#xff08;適合行數較少的情況&#xff09;方法二&#xff1a;利用行列有序特性&#xff08;最優解&#xff09; 4. 代碼實現5. 總結 1. 題目描…

深入理解AVL樹及其旋轉操作

AVL樹的概念 二叉搜索樹雖可以縮短查找的效率&#xff0c;但如果數據有序或接近有序二叉搜索樹將退化為單枝樹&#xff0c;查找元素相當于在順序表中搜索元素&#xff0c;效率低下。因此&#xff0c;兩位俄羅斯的數學家G.M.Adelson-Velskii和E.M.Landis在1962年發明了一種方法…

URL帶有中文會引入哪些問題

處理含中文字符的 URL 1 為什么會出現“亂碼”或崩潰&#xff1f; URL 標準&#xff08;RFC 3986&#xff09;規定&#xff1a;除少數保留字符外&#xff0c;URL 只能包含 ASCII。中文屬于 Unicode&#xff0c;因此必須先轉換。如果直接把 https://example.com/路徑/ 這樣的字…

結構體字段能否單獨加 mut

你問的這個問題在 Rust 里很常見&#xff1a; 一、結構體字段能否單獨加 mut 1. 結構體字段能否單獨加 mut&#xff1f; 不能。Rust 中&#xff0c;mut 是用來修飾變量綁定的&#xff0c;可變性是綁定的屬性&#xff0c;而不是結構體字段本身的屬性。 你不能寫&#xff1a; …

scGPT-spatial 復現

文章目錄 ? 總體流程總覽&#xff08;從 H5AD 到模型訓練&#xff09;&#x1f527; 步驟 1&#xff1a;讀取 H5AD 文件并做基礎預處理&#x1f9f1; 步驟 2&#xff1a;構造訓練樣本輸入&#xff08;token、value&#xff09;&#x1f4e6; 步驟 3&#xff1a;使用 DataColla…

運放電壓跟隨器為什么要加電阻

運放電壓跟隨器為什么要加電阻 我們常見運放的電壓跟隨器如下&#xff1a; 有時候會看見電路中加兩個電阻&#xff1a; 作用就是保護運放&#xff0c;起限流電阻的作用。 當輸入電壓高的時候&#xff0c;運放內部存在鉗位二極管&#xff0c;此電阻就能限流。 并不是所有運放…

MinerU 2.0部署

簡介 MinerU 2.0使用sglang加速&#xff0c;與之前差別較大&#xff0c;建議按照官方的Docker鏡像的方式啟動。 Docker鏡像 Dockerfile 這是官方的Dockerfile # Use the official sglang image FROM lmsysorg/sglang:v0.4.7-cu124# install mineru latest RUN python3 -m …

黑馬python(十七)

目錄&#xff1a; 1.數據可視化-地圖-基礎案例 2.全國疫情地圖 3.河南省疫情地圖繪制 4.基礎柱狀圖構建 5.基礎時間線柱狀圖繪制 6.動態GDP柱狀圖繪制 1.數據可視化-地圖-基礎案例 圖示有點對的不準&#xff0c;可以通過后面的參數 2.全國疫情地圖 3.河南省疫情地圖繪制…

Segment Anything in High Quality之SAM-HQ論文閱讀

摘要 最近的 Segment Anything Model(SAM)在擴展分割模型規模方面取得了重大突破,具備強大的零樣本能力和靈活的提示機制。盡管 SAM 在訓練時使用了 11 億個掩碼,其掩碼預測質量在許多情況下仍不理想,尤其是對于結構復雜的目標。我們提出了 HQ-SAM,使 SAM 能夠精確地分割…

深入理解_FreeRTOS的內部實現(2)

1.事件組 事件組結構體&#xff1a; 事件組 “不關中斷” 的核心邏輯 事件組操作時&#xff0c;優先選擇 “關調度器” 而非 “關中斷” &#xff0c;原因和實現如下&#xff1a; 關調度器&#xff08;而非關中斷&#xff09; FreeRTOS 提供 taskENTER_CRITICAL()&#xff08;…

【圖論題典】Swift 解 LeetCode 最小高度樹:中心剝離法詳解

文章目錄 摘要描述題解答案題解代碼分析思路來源&#xff1a;樹的“中心剝離法”構造鄰接表和度數組循環剝葉子終止條件 示例測試及結果時間復雜度空間復雜度總結 摘要 樹是一種重要的數據結構&#xff0c;在許多應用里&#xff0c;我們希望選一個根&#xff0c;讓這棵樹的高度…

Docker的介紹與安裝

? Docker 對初學者的簡單解釋和應用場景 1.什么是 Docker&#xff1f; 簡單來說&#xff0c;Docker 就像一個“裝箱子”的工具&#xff0c;這個箱子叫做“容器”。 你寫的程序和它運行需要的環境&#xff08;比如操作系統、軟件、工具&#xff09;都裝進一個箱子里。這個箱…

引導相機:工業自動化的智能之眼,賦能制造業高效升級

在工業自動化浪潮中&#xff0c;精準的視覺引導技術正成為生產效率躍升的關鍵。作為遷移科技——一家成立于2017年、專注于3D工業相機和3D視覺系統的領先供應商&#xff0c;我們深知"引導相機"的核心價值&#xff1a;它不僅是一個硬件設備&#xff0c;更是連接物理世…

智能相機如何重塑工業自動化?遷移科技3D視覺系統的場景革命

從硬件參數到產業價值&#xff0c;解碼高精度視覺系統的落地邏輯 一、工業視覺的“智慧之眼” 遷移科技深耕3D工業相機領域&#xff0c;以“穩定、易用、高回報”為核心理念&#xff0c;打造覆蓋硬件、算法、軟件的全棧式視覺系統。成立6年累計融資數億元的背后&#xff0c;是…

【數據挖掘】聚類算法學習—K-Means

K-Means K-Means是一種經典的無監督學習算法&#xff0c;用于將數據集劃分為K個簇&#xff08;clusters&#xff09;&#xff0c;使得同一簇內的數據點相似度高&#xff0c;不同簇間的相似度低。它在數據挖掘、模式識別和機器學習中廣泛應用&#xff0c;如客戶細分、圖像壓縮和…

linux環境內存滿php-fpm

檢查 PHP-FPM 配置 pm.max_children&#xff1a;該參數控制 PHP-FPM 進程池中最大允許的子進程數。過高的子進程數會導致內存占用過大。你可以根據服務器的內存大小來調整 pm.start_servers&#xff1a;控制 PHP-FPM 啟動時創建的進程數。根據實際情況調整此值。 pm.min_spare_…

基于CNN卷積神經網絡圖像識別小程序9部合集

基于CNN卷積神經網絡圖像識別小程序合集-視頻介紹下自取 ? 內容包括&#xff1a; 基于python深度學習的水果或其他物體識別小程序 003基于python深度學習的水果或其他物體識別小程序_嗶哩嗶哩_bilibili 代碼使用的是python環境pytorch深度學習框架&#xff0c;代碼的環境安…

WebRTC(九):JitterBuffer

JitterBuffer Jitter “Jitter”指的是連續到達的媒體包之間時間間隔的變化。在網絡傳輸中&#xff0c;由于&#xff1a; 網絡擁塞路由路徑變化隊列排隊不同鏈路帶寬差異 導致包之間的接收時間不一致&#xff0c;這就是網絡“抖動”。 作用 **JitterBuffer&#xff08;抖…