【设计模式】观察者模式深度讲解

文章目录

    • 概览
      • 一、定义与特点
      • 二、角色与职责
      • 三、实现方式
      • 四、应用场景
      • 五、优缺点
    • 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.mzph.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…