【設計模式】觀察者模式深度講解

文章目錄

    • 概覽
      • 一、定義與特點
      • 二、角色與職責
      • 三、實現方式
      • 四、應用場景
      • 五、優缺點
    • Java實現
    • Python實現

概覽

觀察者模式(Observer Pattern)是一種行為型設計模式,它定義了一種一對多的依賴關系,讓多個觀察者對象同時監聽某一個主題對象。當這個主題對象的狀態發生變化時,會通知所有觀察者對象,使它們能夠自動更新。以下是關于觀察者模式的詳細介紹:

一、定義與特點

  1. 定義:觀察者模式是一種對象行為模式,用于在對象之間建立一對多的依賴關系,以便當一個對象的狀態發生變化時,所有依賴于它的對象都得到通知并被自動更新。
  2. 特點
    • 松耦合:主題和觀察者之間通過抽象接口進行交互,使得它們可以獨立演化而不影響彼此。
    • 一對多關系:一個主題可以有多個觀察者,并且它們之間沒有直接聯系。
    • 可擴展性:可以隨時增加新的觀察者或刪除現有觀察者。
    • 實時性:實現了實時更新機制,當主題狀態改變時能夠即刻通知相關觀察者。

二、角色與職責

在觀察者模式中,通常包含以下幾個角色:

  1. 抽象主題(Subject)角色:把所有觀察者對象保存在一個集合里,提供注冊和刪除觀察者對象的接口。
  2. 具體主題(ConcreteSubject)角色:實現抽象主題角色所提供的接口,當內部狀態發生改變時,給所有注冊的觀察者發出通知。
  3. 抽象觀察者(Observer)角色:為所有的具體觀察者定義一個接口,在得到主題的通知時更新自己。
  4. 具體觀察者(ConcreteObserver)角色:實現抽象觀察者角色所要求的更新接口,以便在得到主題的通知時更新自身的狀態。

三、實現方式

觀察者模式的實現方式多種多樣,但從根本上說,必須包含觀察者和被觀察對象兩個角色。通常,會定義一個觀察者接口和一個主題接口,然后創建具體的觀察者和主題類來實現這些接口。主題類中會維護一個觀察者列表,并在狀態改變時遍歷通知所有觀察者。

四、應用場景

觀察者模式在實際應用中具有廣泛的應用場景,包括但不限于以下幾個方面:

  1. 事件處理:在圖形用戶界面(GUI)框架中,按鈕的點擊事件、窗口的打開和關閉事件等都可以使用觀察者模式進行處理。
  2. 消息通知:在消息通知系統中,當發布者發布新消息時,訂閱該消息的觀察者將收到通知并進行相應的處理。
  3. 發布-訂閱系統:觀察者模式是發布-訂閱模式的核心。當發布者發布新消息或事件時,所有訂閱者都會收到通知并執行相應的操作。
  4. 實時數據更新:在需要實時更新數據的應用中,觀察者模式可以用于將數據源與數據消費者連接起來。當數據源的數據發生變化時,觀察者可以自動獲取最新的數據并進行處理。
  5. 庫和框架:許多編程庫和框架使用觀察者模式來支持插件和擴展。開發人員可以編寫自定義觀察者以響應庫或框架中的事件或回調。
  6. 股票市場監測:股票市場應用程序可以使用觀察者模式來監測股票價格變化,并將這些變化通知給投資者。
  7. 游戲開發:在游戲中,觀察者模式可用于處理各種事件,如玩家輸入、碰撞檢測、角色狀態變化等。
  8. 網絡通信:在網絡應用中,觀察者模式可用于實現即時通信系統,其中用戶之間的消息傳遞可以通過觀察者模式來實現。

五、優缺點

  1. 優點

    • 降低了對象之間的耦合度:觀察者模式使得主題和觀察者之間通過抽象接口進行交互,從而降低了它們之間的耦合度。
    • 增強了系統的可擴展性:由于觀察者模式采用了一對多的依賴關系,因此可以很方便地增加新的觀察者。
    • 實現了實時更新機制:當主題狀態改變時,能夠即刻通知相關觀察者,從而實現實時更新。
  2. 缺點

    • 如果觀察者數量過多,可能會影響性能:因為主題需要遍歷所有觀察者并通知它們狀態的變化,所以如果觀察者數量過多,可能會影響系統的性能。
    • 主題只知道觀察者發生了變化,但不知道具體發生了什么變化:這可能導致觀察者無法做出準確的響應。

綜上所述,觀察者模式是一種非常有用的設計模式,它能夠在對象之間建立松耦合的依賴關系,實現對象之間的動態聯動和實時更新。然而,在使用時也需要注意其潛在的缺點和限制。

Java實現

在Java中,觀察者模式可以通過接口和類來實現。以下是一個簡單的觀察者模式的Java代碼示例,包括抽象主題(Subject)、具體主題(ConcreteSubject)、抽象觀察者(Observer)和具體觀察者(ConcreteObserver)。

首先,我們定義抽象主題接口Subject,它包含注冊、刪除和通知觀察者的方法:

// 抽象主題接口
public interface Subject {// 注冊觀察者void registerObserver(Observer observer);// 刪除觀察者void removeObserver(Observer observer);// 通知所有觀察者void notifyObservers();
}

接著,我們定義抽象觀察者接口Observer,它包含一個更新方法,用于在主題狀態改變時更新觀察者:

// 抽象觀察者接口
public interface Observer {// 更新觀察者void update(String message);
}

然后,我們實現具體主題類ConcreteSubject,它實現了Subject接口,并維護一個觀察者列表:

import java.util.ArrayList;
import java.util.List;// 具體主題類
public class ConcreteSubject implements Subject {private 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();}// 獲取狀態(通常不需要,但為了完整性而提供)public String getState() {return state;}
}

最后,我們實現具體觀察者類ConcreteObserver,它實現了Observer接口:

// 具體觀察者類
public class ConcreteObserver implements Observer {private String name;public ConcreteObserver(String name) {this.name = name;}@Overridepublic void update(String message) {System.out.println(name + " received message: " + message);}
}

現在,我們可以使用這些類來測試觀察者模式:

public class ObserverPatternDemo {public static void main(String[] args) {// 創建具體主題ConcreteSubject subject = new ConcreteSubject();// 創建具體觀察者Observer observer1 = new ConcreteObserver("Observer 1");Observer observer2 = new ConcreteObserver("Observer 2");Observer observer3 = new ConcreteObserver("Observer 3");// 注冊觀察者subject.registerObserver(observer1);subject.registerObserver(observer2);subject.registerObserver(observer3);// 改變主題狀態并通知觀察者subject.setState("State has changed!");// 刪除一個觀察者subject.removeObserver(observer2);// 再次改變主題狀態并通知剩余的觀察者subject.setState("Another state change.");}
}

運行ObserverPatternDemo類的main方法,你將看到以下輸出:

Observer 1 received message: State has changed!
Observer 2 received message: State has changed!
Observer 3 received message: State has changed!
Observer 1 received message: Another state change.
Observer 3 received message: Another state change.

注意,在第二次狀態改變時,Observer 2不再收到通知,因為它已經被從觀察者列表中刪除了。這就是一個簡單的Java觀察者模式的實現。

Python實現

在Python中,觀察者模式可以通過類和接口(在Python中通常使用抽象基類代替接口)來實現。以下是一個簡單的Python實現觀察者模式的示例。

首先,我們定義一個抽象基類Observer,它包含一個update方法,該方法將在主題狀態改變時被調用:

from abc import ABC, abstractmethodclass Observer(ABC):@abstractmethoddef update(self, message: str):pass

接著,我們定義一個Subject類,它維護一個觀察者列表,并提供注冊、刪除和通知觀察者的方法:

class Subject:def __init__(self):self._observers = []def register_observer(self, observer: Observer):self._observers.append(observer)def remove_observer(self, observer: Observer):self._observers.remove(observer)def notify_observers(self, message: str):for observer in self._observers:observer.update(message)# 通常還會有一個設置狀態的方法,這里為了簡單起見,直接提供notify_observers的調用def set_state(self, state: str):message = f"State has changed to: {state}"self.notify_observers(message)

現在,我們可以創建一個具體的觀察者類,它繼承自Observer抽象基類,并實現update方法:

class ConcreteObserver(Observer):def __init__(self, name: str):self.name = namedef update(self, message: str):print(f"{self.name} received message: {message}")

最后,我們可以編寫一些代碼來測試這個觀察者模式:

if __name__ == "__main__":# 創建主題subject = Subject()# 創建觀察者observer1 = ConcreteObserver("Observer 1")observer2 = ConcreteObserver("Observer 2")observer3 = ConcreteObserver("Observer 3")# 注冊觀察者subject.register_observer(observer1)subject.register_observer(observer2)subject.register_observer(observer3)# 改變狀態并通知觀察者subject.set_state("New State")# 刪除一個觀察者subject.remove_observer(observer2)# 再次改變狀態并通知剩余的觀察者subject.set_state("Another New State")

運行上述代碼,你將看到以下輸出:

Observer 1 received message: State has changed to: New State
Observer 2 received message: State has changed to: New State
Observer 3 received message: State has changed to: New State
Observer 1 received message: State has changed to: Another New State
Observer 3 received message: State has changed to: Another New State

注意,在第二次狀態改變時,Observer 2不再收到通知,因為它已經被從觀察者列表中刪除了。

這個示例展示了如何在Python中實現觀察者模式。通過使用抽象基類和具體的觀察者類,我們可以輕松地擴展和修改這個模式以適應不同的需求。

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

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

相關文章

Elasticsearch:ES|QL 中的全文搜索 - 8.17

細心的開發者如果已經閱讀我前兩天發布的文章 “Elastic 8.17&#xff1a;Elasticsearch logsdb 索引模式、Elastic Rerank 等”&#xff0c;你就會發現在 8.17 的發布版中&#xff0c;有一個重要的功能發布。那就是 ES|QL 開始支持全文搜索了。在今天的文章中我們來嘗試一下。…

SQL和Python 哪個更容易自學?

SQL和Python不是一個物種&#xff0c;Python肯定更難學習。如果你從事數據工作&#xff0c;我建議先學SQL、有余力再學Python。因為SQL不光容易學&#xff0c;而且前期的投入產出比更大。 SQL是數據查詢語言&#xff0c;場景限于數據查詢和數據庫的管理&#xff0c;對大部分數據…

【unity】從零開始制作平臺跳躍游戲--界面的認識,添加第一個角色!

在上一篇文章中&#xff0c;我們已經完成了unity的環境配置與安裝?? 【Unity】環境配置與安裝-CSDN博客 接下來&#xff0c;讓我們開始新建一個項目吧&#xff01; 新建項目 首先進入unityHub的項目頁面&#xff0c;點擊“新項目”&#xff1a; 我們這個系列將會以2D平臺…

怎么禁用 vscode 中點擊 go 包名時自動打開瀏覽器跳轉到 pkg.go.dev

本文引用怎么禁用 vscode 中點擊 go 包名時自動打開瀏覽器跳轉到 pkg.go.dev 在 vscode 設置項中配置 gopls 的 ui.navigation.importShortcut 為 Definition 即可。 "gopls": {"ui.navigation.importShortcut": "Definition" }ui.navigation.i…

Unity3D實現抽象類的應用場景例子

系列文章目錄 unity知識點 文章目錄 系列文章目錄??前言??一、示例??二、使用步驟??三、抽象類和接口的區別??3-1、抽象類??3-2、接口類??壁紙分享??總結??前言 假設我們正在制作一個游戲,游戲中有多種不同類型的角色,這些角色都有一些共同的行為(比如移…

數據倉庫工具箱—讀書筆記01(數據倉庫、商業智能及維度建模初步)

數據倉庫、商業智能及維度建模初步 記錄一下讀《數據倉庫工具箱》時的思考&#xff0c;摘錄一些書中關于維度建模比較重要的思想與大家分享&#x1f923;&#x1f923;&#x1f923; 博主在這里先把這本書"變薄"~有時間的小伙伴可以親自再讀一讀&#xff0c;感受一下…

docker啟動一個helloworld(公司內網服務器)

這里寫目錄標題 容易遇到的問題&#xff1a;1、docker連接問題 我來介紹幾種啟動 Docker Hello World 的方法&#xff1a; 最簡單的方式&#xff1a; docker run hello-world這會自動下載并運行官方的 hello-world 鏡像。 使用 Nginx 作為 Hello World&#xff1a; docker…

計算機組成原理(五):程序裝載

在計算機組成原理中&#xff0c;程序裝載&#xff08;Program Loading&#xff09;是指將程序從外存&#xff08;如磁盤&#xff09;加載到內存中&#xff0c;并為其運行做好準備的過程。程序裝載是實現程序從靜態存儲狀態到動態運行狀態的關鍵環節&#xff0c;涉及地址映射、內…

Python+OpenCV系列:模版匹配

文章目錄 1. 模板匹配基本原理2. cv2.matchTemplate() 函數函數原型&#xff1a; 3. 模板匹配步驟4. 單目標模板匹配示例5. 多目標模板匹配多目標模板匹配示例代碼解析&#xff1a; 6. 多模板匹配多模板匹配示例代碼解析 7. 總結 模板匹配是一種在圖像中尋找模板的位置的方法。…

基于IEEE 802.1Qci的時間敏感網絡(TSN)主干架構安全分析及異常檢測系統設計

中文標題&#xff1a;基于IEEE 802.1Qci的時間敏感網絡&#xff08;TSN&#xff09;主干架構安全分析及異常檢測系統設計 英文標題&#xff1a;Security Analysis of the TSN Backbone Architecture and Anomaly Detection System Design Based on IEEE 802.1Qci 作者信息&…

怎樣提升企業網絡的性能?

企業網絡的穩定性和高效性直接影響員工的工作效率。以下從多維度分析了一些有效策略&#xff0c;幫助公司提升網絡性能&#xff0c;營造更高效的辦公環境。 1. 升級網絡設備 采用性能更高的網絡硬件是優化網絡體驗的重要基礎。選擇支持高吞吐量、低延遲的設備&#xff08;如企業…

scala基礎_數據類型概覽

Scala 數據類型 下表列出了 Scala 支持的數據類型&#xff1a; 類型類別數據類型描述Scala標準庫中的實際類基本類型Byte8位有符號整數&#xff0c;數值范圍為 -128 到 127scala.Byte基本類型Short16位有符號整數&#xff0c;數值范圍為 -32768 到 32767scala.Short基本類型I…

力扣239.滑動窗口最大值

文章目錄 一、前言二、單調隊列 一、前言 力扣239.滑動窗口最大值 滑動窗口最大值&#xff0c;這道題給定一個數組&#xff0c;以及一個窗口的長度&#xff0c;這個窗口會往后滑動&#xff0c;直到數組最后一個元素。 要求每個滑動窗口的中的最大值。對于這道題&#xff0c;我…

mac 安裝CosyVoice (cpu版本)

CosyVoice 介紹 CosyVoice 是阿里研發的一個tts大模型 官方項目地址&#xff1a;https://github.com/FunAudioLLM/CosyVoice.git 下載項目&#xff08;非官方&#xff09; git clone --recursive https://github.com/v3ucn/CosyVoice_for_MacOs.git 進入項目 cd CosyVoic…

電腦插件修復工具

DirectX修復工具 鏈接&#xff1a;夸克網盤分享

Maven 安裝配置(詳細教程)

文章目錄 一、Maven 簡介二、下載 Maven三、配置 Maven3.1 配置環境變量3.2 Maven 配置3.3 IDEA 配置 四、結語 一、Maven 簡介 Maven 是一個基于項目對象模型&#xff08;POM&#xff09;的項目管理和自動化構建工具。它主要服務于 Java 平臺&#xff0c;但也支持其他編程語言…

Scala中的泛型特質

代碼如下&#xff1a; package test41 //泛型特質 object test3 { //定義一個日志//泛型特質&#xff0c;X是泛型名稱&#xff0c;可以更改。trait Logger[X] {val content: Xdef show():Unit }class FileLogger extends Logger[String] {override val content: String "…

前端三大框架 Vue、React 和 Angular 的市場占比分析

一、引言 ?? 隨著前端技術的迅速發展&#xff0c;Vue.js、React 和 Angular 已成為全球最受歡迎的三大前端框架。在國內外&#xff0c;不同的框架在市場中的占比和流行程度存在顯著差異。本文將從全球和中國市場的角度&#xff0c;對這三大框架的市場占比進行分析&#xff0…

vue3+echarts+websocket分時圖與K線圖實時推送

一、父組件代碼&#xff1a; <template> <div class"chart-box" v-loading"loading"> <!-- tab導航欄 --> <div class"tab-box"> <div class"tab-list"> <div v-for"(item, index) in tabList…

用python的flask寫的一個MQTT中轉功能,http的方式發送數據和接收數據

需求背景 給一個客戶對接人臉識別的設備&#xff0c;最后需要通知服務端進行一些消息推送。 簡單例子 # 作者 陳老師 # https://v.iiar.cn import json import paho.mqtt.client as mqtt import requests from flask import Flask, requestapp Flask(__name__)# MQTT配置 mq…