設計模式基礎概念(行為模式):觀察者模式(Observer)

概述

我們可以發現這樣一個場景:如果你訂閱了一份雜志或報紙, 那就不需要再去報攤查詢新出版的刊物了。

  • 出版社 (即應用中的 “發布者(publisher)”) 會在刊物出版后 (甚至提前) 直接將最新一期寄送至你的郵箱中。

    出版社負責維護訂閱者(subscribers)列表, 了解訂閱者對哪些刊物感興趣。

  • 當訂閱者希望出版社停止寄送新一期的雜志時, 他們可隨時從該列表中退出。

觀察者模式(Observer)是一種行為設計模式, 允許你定義一種訂閱機制, 可在對象事件發生時通知多個 “觀察” 該對象的其他對象

  • 擁有一些值得關注的狀態的對象通常被稱為目標
  • 由于它要將自身的狀態改變通知給其他對象, 我們也將其稱為發布者 (publisher)
  • 所有希望關注發布者狀態變化的其他對象被稱為訂閱者 (subscribers)

結構如下

其具體的結構如下
在這里插入圖片描述

場景選擇

當一個對象狀態的改變需要改變其他對象, 或實際對象是事先未知的或動態變化的時, 可使用觀察者模式。

  • 當你使用圖形用戶界面類時通常會遇到一個問題。

    比如, 你創建了自定義按鈕類并允許客戶端在按鈕中注入自定義代碼, 這樣當用戶按下按鈕時就會觸發這些代碼。

  • 觀察者模式允許任何實現了訂閱者接口的對象訂閱發布者對象的事件通知。

    可在按鈕中添加訂閱機制, 允許客戶端通過自定義訂閱類注入自定義代碼。

當應用中的一些對象必須觀察其他對象時, 可使用該模式。 但僅能在有限時間內或特定情況下使用

  • 訂閱列表是動態的, 因此訂閱者可隨時加入或離開該列表

目前代碼中的實際應用

應用示例: 觀察者模式在 Java 代碼中很常見, 特別是在 GUI 組件中。 它提供了在不與其他對象所屬類耦合的情況下對其事件做出反應的方式

下面是核心 Java 程序庫中該模式的一些示例:

  • java.util.Observer/java.util.Observable (極少在真實世界中使用)
  • java.util.EventListener的所有實現 (幾乎廣泛存在于 Swing 組件中)
  • javax.servlet.http.HttpSessionBindingListener
  • javax.servlet.http.HttpSessionAttributeListener
  • javax.faces.event.PhaseListener

識別方法加粗樣式: 該模式可以通過將對象存儲在列表中的訂閱方法, 和對于面向該列表中對象的更新方法的調用來識別

偽代碼實現

發布者 (Publisher)

發布者 (Publisher) 會向其他對象發送值得關注的事件

  • 事件會在發布者自身狀態改變或執行特定行為后發生
  • 發布者中包含一個允許新訂閱者加入和當前訂閱者離開列表的訂閱構架
  • 新事件發生時, 發送者會遍歷訂閱列表并調用每個訂閱者對象的通知方法。 該方法是在訂閱者接口中聲明的

示例代碼

// 保存所有訂閱此主題的觀察者,觀察者的 數量是任意的。
// 定義 添加觀察者 (Attach) 和 刪除觀察者 (Detach) 的接口。
abstract class Publisher {protected String name;protected String state;protected List<Subscriber> subscribers = new ArrayList<Subscriber>();public abstract String getState();public abstract void setState(String state);// 發布public abstract void Notify();public Publisher(String name) {this.name = name;}// 添加觀察者public void Attach(Subscriber subscriber) {observers.add(observer);}//  刪除觀察者public void Detach(Subscriber subscriber) {observers.remove(observer);}
}

訂閱者 (Subscriber)

訂閱者 (Subscriber) 接口聲明了通知接口

  • 絕大多數情況下, 該接口僅包含一個 update更新方法
  • 該方法可以擁有多個參數, 使發布者能在更新時傳遞事件的詳細信息

示例代碼

// 觀察者類,定義更新接口 (Update),當收到 Subject 的通知時,Observer 需要同步更新信息
abstract class Subscriber {protected String name;// 監聽的發布者protected Publisher publisher;public Subscriber(String name, Publisher publisher) {this.name = name;this.publisher= publisher;}public abstract void Update();
}

上下文信息

訂閱者通常需要一些上下文信息來正確地處理更新。

  • 因此, 發布者通常會將一些上下文數據作為通知方法的參數進行傳遞
  • 發布者也可將自身作為參數進行傳遞, 使訂閱者直接獲取所需的數據

如上示例所示,上下文信息便是status和name

具體發布者 (Concrete Publisher)

具體發布者 (Concrete Publisher)相當于訂閱者需要監聽的類型(因為這個類型有很多種,大部分情況下不可能只有一種發布者)

示例代碼

class ConcretePublisher extends Publisher{public ConcretePublisher(String name) {super(name);}@Overridepublic String getState() {return state;}@Overridepublic void setState(String state) {this.state = state;}@Overridepublic void Notify() {System.out.println("======= " + this.name + "主題發布新消息 =======");for (Subscriber subscriber : subscribers) {subscriber.Update();}}
}

具體訂閱者類(Concrete Subscriber )

具體訂閱者 (Concrete Subscribers) 可以執行一些操作來回應發布者的通知

  • 所有具體訂閱者類都實現了同樣的接口, 因此發布者不需要與具體類相耦合。

ConcreteSubscriber : 具體訂閱者類,實現 Subscriber 的更新接口 (Update),以便和 Publisher 同步狀態信息

示例代碼

class ConcreteSubscriber extends Subscriber {private String state;public ConcretePublisher(String name, Publisher publisher) {super(name, publisher);}@Overridepublic void Update() {state = subject.getState();System.out.println(this.name + "收到當前狀態:" + state);}
}

客戶端 (Client)

客戶端 (Client) 會分別創建發布者和訂閱者對象, 然后為訂閱者注冊發布者更新

示例代碼

public class ObserverPattern {public static void main(String[] args) {ConcretePublisher concretePublisher = new ConcretePublisher("天氣");ConcreteSubscriber sub1 = new ConcreteSubscriber("張三", concretePublisher);ConcreteSubscriber sub2= new ConcreteSubscriber("李四", concretePublisher);ConcreteSubscriber sub3= new ConcreteSubscriber("王五", concretePublisher);concretePublisher.Attach(sub1);concretePublisher.Attach(sub2);concretePublisher.Attach(sub3);concretePublisher.setState("今天下雨");concretePublisher.Notify();concretePublisher.Detach(sub2);concretePublisher.setState("明天天晴");concretePublisher.Notify();}
}
/*
======= 天氣主題發布新消息 =======
張三收到當前狀態:今天下雨
李四收到當前狀態:今天下雨
王五收到當前狀態:今天下雨
======= 天氣主題發布新消息 =======
張三收到當前狀態:明天天晴
王五收到當前狀態:明天天晴*/

實現方式

下面總結一下實現的步驟,大致可分為下面的幾步

  1. 仔細檢查業務邏輯, 試著將其拆分為兩個部分:

    1. 獨立于其他代碼的核心功能將作為發布者
    2. 其他代碼則將轉化為一組訂閱類
  2. 聲明訂閱者接口。 該接口至少應聲明一個 update方法

  3. 聲明發布者接口并定義一些接口來在列表中添加和刪除訂閱對象。

    1. 記住發布者僅通過訂閱者接口與它們進行交互
  4. 確定存放實際訂閱列表的位置并實現訂閱方法

    1. 通常所有類型的發布者代碼看上去都一樣, 因此將列表放置在直接擴展自發布者接口的抽象類中是顯而易見的。 具體發布者會擴展該類從而繼承所有的訂閱行為
    2. 但是, 如果你需要在現有的類層次結構中應用該模式, 則可以考慮使用組合的方式: 將訂閱邏輯放入一個獨立的對象, 然后讓所有實際訂閱者使用該對象。
  5. 創建具體發布者類。 每次發布者發生了重要事件時都必須通知所有的訂閱者。

  6. 在具體訂閱者類中實現通知更新的方法

    1. 絕大部分訂閱者需要一些與事件相關的上下文數據。 這些數據可作為通知方法的參數來傳遞。
    2. 但還有另一種選擇。 訂閱者接收到通知后直接從通知中獲取所有數據。 在這種情況下, 發布者必須通過更新方法將自身傳遞出去。 另一種不太靈活的方式是通過構造函數將發布者與訂閱者永久性地連接起來。
  7. 客戶端必須生成所需的全部訂閱者, 并在相應的發布者處完成注冊工作。

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

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

相關文章

JavaFX實戰:從零到一實現一個功能豐富的“高級反應速度測試”游戲

大家好&#xff01;今天我們不搞簡單的“紅變綠就點”了&#xff0c;來點硬核的&#xff01;我們要用 JavaFX 從頭開始&#xff0c;構建一個更復雜、更有趣也更考驗能力的“高級反應速度測試”游戲。這個版本將引入選擇反應時 (Choice Reaction Time) 的概念——你需要在多個干…

CSS 選擇器介紹

CSS 選擇器介紹 1. 基本概念 CSS&#xff08;層疊樣式表&#xff09;是一種用于描述 HTML 或 XML 文檔外觀的語言。通過 CSS&#xff0c;可以控制網頁中元素的布局、顏色、字體等視覺效果。而 CSS 選擇器則是用來指定哪些 HTML 元素應該應用這些樣式的工具。 2. 基本選擇器 …

Vue3父子組件數據同步方法

在 Vue 3 中&#xff0c;當子組件需要修改父組件傳遞的數據副本并同步更新時&#xff0c;可以通過以下步驟實現&#xff1a; 方法 1&#xff1a;使用 v-model 和計算屬性&#xff08;實時同步&#xff09; 父組件&#xff1a; vue <template><ChildComponent v-mo…

el-table中el-input的autofocus無法自動聚焦的解決方案

需求 有一個表格展示了一些進度信息&#xff0c;進度信息可以修改&#xff0c;需要點擊進度信息旁邊的編輯按鈕時&#xff0c;把進度變為輸入框且自動聚焦&#xff0c;當鼠標失去焦點時自動請求更新接口。 注&#xff1a;本例以vue2 element UI為例 分析 這個需求看著挺簡單…

用高斯濺射技術跨越機器人模擬與現實的鴻溝:SplatSim 框架解析

在機器人領域&#xff0c;讓機器人在現實世界中精準執行任務是大家一直追求的目標。可模擬環境和現實世界之間存在著不小的差距&#xff0c;特別是基于 RGB 圖像的操作策略&#xff0c;從模擬轉移到現實時總是狀況百出。 今天咱們就來聊聊 SplatSim 框架&#xff0c;看看它是怎…

【自然語言處理與大模型】如何知道自己部署的模型的最大并行訪問數呢?

當你自己在服務器上部署好一個模型后&#xff0c;使用場景會有兩種。第一種就是你自己去玩&#xff0c;結合自有的數據做RAG等等&#xff0c;這種情況下一般是不會考慮并發的問題。第二種是將部署好的服務給到別人來使用&#xff0c;這時候就必須知道我的服務到底支持多大的訪問…

[FPGA基礎] UART篇

Xilinx FPGA UART 硬件接口使用指南 1. 引言 UART (通用異步收發器) 是一種廣泛使用的串行通信接口&#xff0c;因其簡單、可靠和易于實現而成為 Xilinx FPGA 設計中的常見硬件接口。UART 用于在 FPGA 與外部設備&#xff08;如 PC、微控制器、傳感器等&#xff09;之間進行數…

【Netty4核心原理】【全系列文章目錄】

文章目錄 一、前言二、目錄 一、前言 本系列雖說本意是作為 《Netty4 核心原理》一書的讀書筆記&#xff0c;但在實際閱讀記錄過程中加入了大量個人閱讀的理解和內容&#xff0c;因此對書中內容存在大量刪改。 本系列內容基于 Netty 4.1.73.Final 版本&#xff0c;如下&#xf…

用 PyTorch 和numpy分別實現簡單的 CNN 二分類器

作業用到的知識&#xff1a; 1.Pytorch: 1. nn.Conv2d&#xff08;二維卷積層&#xff09; 作用&#xff1a; 對輸入的多通道二位數據&#xff08;如圖像&#xff09;進行特征提取&#xff0c;通過滑動卷積核計算局部區域的加權和&#xff0c;生成新的特征圖。 關鍵參數&a…

使用n8n構建自動化工作流:從數據庫查詢到郵件通知的使用指南

n8n是一款強大的開源工作流自動化工具&#xff0c;可以幫助你將各種服務和應用程序連接起來&#xff0c;創建復雜的自動化流程。下面我將詳細介紹一個實用的n8n用例&#xff1a;從MySQL數據庫查詢數據并發送郵件通知&#xff0c;包括使用場景、搭建步驟和節點部署方法。 使用場…

Vscode已經打開的python項目,如何使用已經建立的虛擬環境

在 VS Code 中使用已創建的 Conda/Mamba 虛擬環境 pe100&#xff0c;只需以下幾步&#xff1a; 步驟 1&#xff1a;確保虛擬環境已存在 在終端運行以下命令&#xff0c;檢查 pe100 環境是否已正確創建&#xff1a; conda activate pe100 python --version # 應顯示 Python 3…

Volatility工具學習

背景 VMware虛擬機系統hang死&#xff0c;手動重啟無法觸發系統panic&#xff0c;從而不能觸發kdump產生vmcore文件進行原因分析&#xff1b;此種情況下需要手動生成虛擬機內存快照&#xff0c;進而利用Volatility工具分析系統hang死的具體原因。 配置 使用VMware創建虛擬機…

學習筆記(C++篇)--- Day 4

目錄 1.賦值運算符重載 1.1 運算符重載 1.2 賦值運算符重載 1.3 日期類實現 1.賦值運算符重載 1.1 運算符重載 ①當運算符被用于類類型的對象時&#xff0c;C語言允許我們通過通過運算符重載的形式指定新的含義。C規定類類型對象使用運算符時&#xff0c;必須轉換成調用對…

Docker 快速入門教程

1. Docker 基本概念 鏡像(Image): 只讀模板&#xff0c;包含創建容器的指令 容器(Container): 鏡像的運行實例 Dockerfile: 用于構建鏡像的文本文件 倉庫(Repository): 存放鏡像的地方&#xff08;如Docker Hub&#xff09; 2. 安裝Docker 根據你的操作系統選擇安裝方式:…

vue項目中使用tinymce富文本編輯器

vue使用tinymce 文章目錄 vue使用tinymcetinymce富文本編輯器在這里插入圖片描述 一、本文要實現二、使用步驟1.安裝tinymce2.tinymce組件新建3. 在store添加商品詳情的狀態管理4. tinymce組件的引入 tinymce富文本編輯器 提示&#xff1a;以下是本篇文章正文內容&#xff0c;下…

簡單適配torch_npu不支持的ATen算子

簡單適配torch_npu不支持的ATen算子 一、背景說明1.1 PyTorch擴展機制1.2 核心概念二、實現步驟詳解2.1 實現前向、反向傳播算子2.2 編譯生成動態庫2.3 測試驗證程序三、關鍵點解析3.1 設計注意事項3.2 性能優化方向四、驗證結果一、背景說明 1.1 PyTorch擴展機制 PrivateUse1…

同樣的html標記,不同語言的文本,顯示的字體和粗細會不一樣嗎

同樣的 HTML 標記&#xff0c;在不同語言的文本下&#xff0c;顯示出來的字體和粗細確實可能會不一樣&#xff0c;原因如下&#xff1a; &#x1f30d; 不同語言默認字體不同 瀏覽器字體回退機制 CSS 里寫的字體如果當前系統不支持&#xff0c;就會回退到下一個&#xff0c;比如…

基于 Spring Boot 瑞吉外賣系統開發(六)

基于 Spring Boot 瑞吉外賣系統開發&#xff08;六&#xff09; 菜品列表 在系統管理端首頁&#xff0c;單擊左側菜單欄中的“菜品管理”&#xff0c;會在右側打開菜品管理頁面。 請求URL/dish/page&#xff0c;請求方法GET,請求參數page&#xff0c;pageSize。 該菜品列表…

計算機視覺與深度學習 | TensorFlow基本概念與應用場景:MNIST 手寫數字識別(附代碼)

TensorFlow 基本概念 TensorFlow 是一個開源的機器學習框架,由 Google 開發,核心概念包括: 張量(Tensor):多維數組,是數據的基本單位。計算圖(Graph):早期版本中用于描述數據流和計算過程,2.x 默認啟用即時執行(Eager Execution),兼顧靈活性和性能。層(Layers)…

vue+django+LSTM微博輿情分析系統 | 深度學習 | 食品安全分析

文章結尾部分有CSDN官方提供的學長 聯系方式名片 文章結尾部分有CSDN官方提供的學長 聯系方式名片 關注B站&#xff0c;有好處&#xff01; 編號&#xff1a; D031 LSTM 架構&#xff1a;vuedjangoLSTMMySQL 功能&#xff1a; 微博信息爬取、情感分析、基于負面消極內容輿情分析…