设计模式 行为型 观察者模式(Observer Pattern)与 常见技术框架应用 解析

在这里插入图片描述

观察者模式(Observer Pattern)是一种行为设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新。

一、核心思想

观察者模式的核心思想是解耦主题(被观察者)和观察者,使得它们可以独立变化而不会相互影响。这有助于降低对象之间的耦合度,提高系统的可扩展性和可维护性。

二、定义与结构

1. 定义

观察者模式定义了对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。

2. 结构

  • Subject(主题):也称为被观察者,它是一个接口或者抽象类,定义了添加、删除和通知观察者的方法。它维护了一个观察者列表,当自身状态发生变化时,通过遍历这个列表来通知所有的观察者。
  • ConcreteSubject(具体主题):实现了Subject接口,它包含了一些可以被观察的状态属性,并且在这些状态发生变化时,负责调用通知方法来通知观察者。
  • Observer(观察者):也是一个接口或者抽象类,它定义了一个更新方法,用于在收到主题通知时更新自己的状态。
  • ConcreteObserver(具体观察者):实现了Observer接口,它包含了用于存储自身状态的属性,并且实现了更新方法,在更新方法中根据主题传递过来的信息更新自己的状态。

三、角色

1. 主题(Subject)

  • 职责是管理观察者对象的引用列表,提供添加和删除观察者的方法。
  • 当自身状态发生变化时,负责通知所有已注册的观察者。

2. 观察者(Observer)

  • 定义了一个更新接口,当收到主题的通知时,会调用这个更新接口来更新自己的状态。

四、实现步骤及代码示例

1. 定义观察者接口

// 观察者接口
public interface Observer {void update(String news);
}

2. 定义主题接口

import java.util.ArrayList;
import java.util.List;// 主题接口
public interface Subject {void attach(Observer observer);void detach(Observer observer);void notifyObservers(String news);
}

3. 实现具体主题类

import java.util.ArrayList;
import java.util.List;// 具体主题类
public class NewsPublisher implements Subject {private List<Observer> observers = new ArrayList<>();private String latestNews;@Overridepublic void attach(Observer observer) {observers.add(observer);}@Overridepublic void detach(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers(String news) {this.latestNews = news;for (Observer observer : observers) {observer.update(latestNews);}}
}

4. 实现具体观察者类

// 具体观察者类
public class NewsSubscriber implements Observer {private String name;public NewsSubscriber(String name) {this.name = name;}@Overridepublic void update(String news) {System.out.println(name + " received news: " + news);}
}

5. 测试代码

public class Main {public static void main(String[] args) {NewsPublisher publisher = new NewsPublisher();NewsSubscriber subscriber1 = new NewsSubscriber("Subscriber 1");NewsSubscriber subscriber2 = new NewsSubscriber("Subscriber 2");publisher.attach(subscriber1);publisher.attach(subscriber2);publisher.notifyObservers("New technology released!");}
}

五、常见技术框架应用

1、Vue 2 数据劫持

在Vue 2中,观察者模式是通过Object.defineProperty()方法实现的,这允许Vue能够追踪数据对象属性的变化,并在变化发生时触发相应的更新。以下是对Vue 2中基于Object.defineProperty()实现的观察者模式的详细解析:

1.1. 数据劫持

Vue 2 使用Object.defineProperty()来对数据对象的属性进行劫持。这个方法允许我们定义一个对象属性的getter和setter函数,当属性被访问或修改时,这些函数会被调用。

Object.defineProperty(obj, 'property', {get: function() {// 当属性被访问时执行的代码},set: function(newValue) {// 当属性被修改时执行的代码}
});

在Vue中,当数据对象被创建时,Vue会使用Object.defineProperty()遍历对象的所有属性,并为它们设置getter和setter。这样,当这些属性在将来被访问或修改时,Vue就能够感知到。

1.2. 依赖收集

在getter函数中,Vue会进行依赖收集。所谓依赖收集,就是当某个属性被访问时,Vue会记录下当前正在执行的Watcher(观察者)。Watcher是Vue内部用于追踪数据变化的机制,它会在数据变化时触发相应的更新。

当组件渲染或计算属性被计算时,它们会访问数据对象的属性,这时getter函数就会被调用,Vue就会记录下当前的Watcher。

1.3. 派发更新

在setter函数中,当数据属性被修改时,Vue会触发setter函数。在这个函数中,Vue会遍历之前收集的依赖(Watcher),并通知它们数据已经发生了变化,需要重新执行以更新视图或计算属性。

1.4. 观察者(Watcher)

Watcher是Vue内部的一个类,它用于追踪数据的变化并在数据变化时执行相应的回调函数。在Vue中,Watcher有三种类型:

  • 渲染Watcher:与组件的渲染函数相关联,当数据变化时,它会重新渲染组件。
  • 计算属性Watcher:与计算属性相关联,当计算属性的依赖数据变化时,它会重新计算计算属性的值。
  • 侦听器Watcher:通过vm.$watch方法创建的Watcher,用于在数据变化时执行特定的回调函数。

1.5. 实现细节

Vue 2的内部实现非常复杂,但基于上述原理,我们可以简化地理解其观察者模式的实现过程:

  1. 初始化数据:使用Object.defineProperty()为数据对象的每个属性设置getter和setter。
  2. 依赖收集:在getter函数中,检查当前是否存在活动的Watcher(通常是在组件渲染或计算属性计算时),如果存在,则将其添加到该属性的依赖列表中。
  3. 派发更新:在setter函数中,当属性值发生变化时,遍历该属性的依赖列表,并通知每个依赖(Watcher)数据已经变化,需要执行更新操作。

1.6. 注意事项

  • 由于Object.defineProperty()只能对对象的已有属性进行劫持,因此Vue无法检测到对象属性的添加或删除。为了解决这个问题,Vue提供了Vue.set()Vue.delete()方法。
  • 深度监听:默认情况下,Vue只监听对象的第一层属性的变化。如果需要监听嵌套对象的变化,可以在创建Vue实例时通过observe选项开启深度监听(但请注意性能开销)。然而,在Vue 2中,深度监听通常是通过递归地为嵌套对象设置getter和setter来实现的,而不是简单地通过observe选项。实际上,observe选项在Vue 2中并不直接控制深度监听。
  • 响应式系统的局限性:由于JavaScript的限制和性能考虑,Vue的响应式系统有一些局限性。例如,它不能检测数组元素通过索引的直接修改或对象属性的添加/删除(除非使用Vue.set()/Vue.delete())。

综上所述,Vue 2通过Object.defineProperty()实现了观察者模式,使得Vue能够追踪数据对象属性的变化并在变化发生时自动更新视图。然而,由于JavaScript的限制和性能考虑,Vue的响应式系统有一些局限性需要注意。

2. JavaScript 中 事件监听

// 创建一个按钮元素
const button = document.createElement('button');
button.textContent = 'Click me';// 定义观察者函数(事件处理函数)
const observerFunction = function () {console.log('Button was clicked!');
};// 主题(按钮)添加观察者(事件监听)
button.addEventListener('click', observerFunction);// 将按钮添加到文档中
document.body.appendChild(button);

在这个JavaScript示例中,button是主题,observerFunction是观察者。当按钮被点击(主题状态改变)时,会触发观察者函数,这类似于观察者模式的通知机制。

六、应用场景

当一个对象的改变需要同时改变其他对象,而不知道具体有多少个对象有待改变时。
当一个抽象模型有两个方面,其中一个方面依赖于另一方面,这时可以通过观察者模式将这两者封装在独立的对象中以使它们各自独立地改变和复用。
当对一个对象的改变需要广播到其他对象时。

观察者模式广泛应用于各种需要通知多个对象进行同步更新的场合,包括但不限于:

  1. GUI事件监听机制:在图形用户界面编程中,按钮、文本框等控件的事件处理通常使用观察者模式。
  2. 数据模型与视图同步:在MVC架构中,观察者模式常用于数据模型和视图之间的更新同步。
  3. 发布-订阅系统:观察者模式是发布-订阅系统的基础,允许不同的服务订阅某个主题并接收通知。
  4. 股票价格监控:在金融系统中,观察者模式可以让股票价格的变化自动通知所有依赖该数据的系统。
  5. 社交媒体的通知机制:当用户发布新动态时,所有关注者都会收到通知。

七、优缺点

优点

  1. 解耦性高:主题和观察者之间是松耦合的关系。主题只需要知道观察者实现了更新方法,而不需要了解观察者的具体细节。这样可以方便地添加、删除和替换观察者,同时也使得主题和观察者可以独立地进行修改和扩展。
  2. 支持广播通信:主题可以同时通知多个观察者,使得系统能够方便地实现一对多的消息传递机制,提高了信息传播的效率。

缺点

  1. 可能导致性能问题:如果观察者数量过多,当主题状态发生变化时,通知所有观察者可能会消耗较多的时间和资源。特别是在一些对性能要求较高的场景下,可能需要对通知机制进行优化,比如采用异步通知等方式。
  2. 存在循环依赖风险:如果观察者在更新自己状态的过程中又对主题进行了操作,可能会导致循环依赖,使得系统的逻辑变得复杂,甚至出现死循环等问题。在设计和实现过程中需要特别注意避免这种情况。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/65711.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

03_Redis基本操作

1.Redis查询命令 1.1 官网命查询命令 为了便于学习Redis,官方将其用于操作不同数据类型的命令进行了分类整理。你可以通过访问Redis官方网站上的命令参考页面https://redis.io/commands来查阅这些分组的命令,这有助于更系统地理解和使用Redis的各项功能。 1.2 HELP查询命令…

system securiry: supervisor password required

报错解释&#xff1a; 这个错误表明系统安全模块&#xff08;如SELinux或AppArmor&#xff09;需要超级用户&#xff08;通常是root&#xff09;的密码来确认一个操作。这通常发生在尝试进行某些需要高级权限的系统更改时。 解决方法&#xff1a; 如果你拥有root权限&#xff0…

Ubuntu 如何查看盘是机械盘还是固态盘

在 Ubuntu 系统中&#xff0c;您可以通过以下方法来确定硬盘是机械硬盘&#xff08;HDD&#xff09;还是固态硬盘&#xff08;SSD&#xff09;&#xff1a; 使用 lsblk 命令&#xff1a; 打开终端&#xff0c;输入以下命令&#xff1a; lsblk -d -o name,rota该命令将列出所…

探索式测试

探索式测试是一种软件测试风格&#xff0c;它强调独立测试人员的个人自由和职责&#xff0c;为了持续优化其工作的价值&#xff0c;将测试学习、测试设计、测试执行和测试结果分析作为相互支持的活动&#xff0c;在整个项目实现过程中并行地执行。 选择合适的探索式测试方法我…

uniapp 微信小程序内嵌h5实时通信

描述&#xff1a; 小程序webview内嵌的h5需要向小程序实时发送消息&#xff0c;有人说postMessage可以实现&#xff0c;所以试验一下&#xff0c;结果是实现不了实时&#xff0c;只能在特定时机后退、组件销毁、分享时小程序才能接收到信息&#xff08;小程序为了安全等考虑做了…

php 使用simplexml_load_string转换xml数据格式失败

本文介绍如何使用php函数解析xml数据为数组。 <?php$a <xml><ToUserName><![CDATA[ww8b77afac71336111]]></ToUserName><FromUserName><![CDATA[sys]]></FromUserName><CreateTime>1736328669</CreateTime><Ms…

HOW - Form 表单 label 和 wrapper 对齐场景

一、背景 在日常使用 表单 时&#xff0c;我们一般有如下布局&#xff1a; 可以通过 Form 表单提供的配置直接设置&#xff1a; <Formform{form}labelCol{{ span: 4 }}wrapperCol{{ span: 20 }}onFinish{handleSubmit}><Form.Itemlabel"输入框"name"…

深入探索AI核心模型:CNN、RNN、GAN与Transformer

在人工智能的飞速发展中&#xff0c;众多深度学习模型和算法不断涌现&#xff0c;推动了许多领域的进步。特别是在图像识别、自然语言处理、生成建模等方向&#xff0c;AI模型的应用越来越广泛。本文将介绍几种最常用的AI模型&#xff0c;包括卷积神经网络&#xff08;CNN&…

樱桃键盘win键按了没反应怎么处理

‌游戏模式‌&#xff1a;部分樱桃键盘在进入游戏模式后会禁用Win键&#xff0c;以防止在游戏过程中误触。可以通过按下Fn F9键来切换游戏模式和办公模式&#xff0c;确保键盘处于办公模式下&#xff0c;Win键即可恢复正常功能。‌ &#xff08;至此我的问题已解决&#xff0c…

解析若依 `R.java` 类——ruoyi-common-core

文章目录 1. 类的整体功能2. 代码解析2.1 成员变量和常量2.2 静态方法构造响应对象2.3 内部私有方法 restResult2.4 工具方法 3. 开发中的应用扩展3.1 接口规范化3.2 快速响应构造3.3 自定义状态码3.4 自定义扩展 R.java 是若依框架中通用的 API 响应封装类&#xff0c;主要用于…

Perl语言的数据结构

Perl语言的数据结构 Perl是一种功能强大的、灵活的脚本语言&#xff0c;广泛用于文本处理、系统管理、网络编程以及许多其他领域。其灵活性不仅体现在语法上&#xff0c;还体现在其丰富的数据结构上。本文将深入探讨Perl的主要数据结构&#xff0c;包括标量、数组、哈希以及引…

RK3588上CPU和GPU算力以及opencv resize的性能对比测试

RK3588上CPU和GPU算力以及opencv resize的性能对比测试 一.背景二.小结三.相关链接四.操作步骤1.环境搭建A.安装依赖B.设置GPU为高性能模式C.获取GPU信息D.获取CPU信息 2.调用OpenCL SDK获取GPU信息3.使用OpenCL API计算矩阵乘4.使用clpeak测试GPU的性能5.使用OpenBLAS测试CPU的…

转运机器人在物流仓储行业的优势特点

在智能制造与智慧物流的浪潮中&#xff0c;一款革命性的产品正悄然改变着行业的面貌——富唯智能转运机器人&#xff0c;它以卓越的智能科技与创新的设计理念&#xff0c;引领着物流领域步入一个全新的高效、智能、无人的时代。 一、解放双手&#xff0c;重塑物流生态 富唯智能…

基于单片机的无线智能窗帘控制器的设计

摘 要 : 本文以单片机为控制核心 , 基于 PT2262/ 2272 无线收发模块 , 实现了窗帘的无线远程智能控制 . 该控制器通过高频无线收发模块实现了遥控窗帘的开合控制; 根据外部光线强弱实现自动开关窗帘 ; 根据设定时间自动完成开关过程; 通过语音播报当前环境温湿度信息以…

linux centos挂载未分配的磁盘空间

使用到的命令 lshw -class disk -short hostnamectl fdisk /dev/sdb partprobe /dev/sdb mount /dev/sdb2 /opt/fastdfs/ mkfs.ext4 /dev/sdb2 mount -t ext4 /dev/sdb2 /opt/fastdfs/

Vivado中Tri_mode_ethernet_mac的时序约束、分析、调整——(一)时序约束的基本概念

1、基本概念 推荐阅读&#xff0c;Ally Zhou编写的《Vivado使用误区与进阶》系列文章&#xff0c;熟悉基本概念、tcl语句的使用。 《Vivado使用误区与进阶》电子书开放下载&#xff01;&#xff01; 2、Vivado中的语法例程 1&#xff09;语法例程 约束的语句可以参考vivado…

基于Spring Boot的城市垃圾分类管理系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

springboot整合admin

1. 添加依赖 首先&#xff0c;在你的admin服务端pom.xml文件中添加Spring Boot Admin的依赖&#xff1a; <dependency><groupId>de.codecentric</groupId><artifactId>spring-boot-admin-starter-server</artifactId><version>2.5.4<…

【YOLOv8杂草作物目标检测】

YOLOv8杂草目标检测 算法介绍模型和数据集下载 算法介绍 YOLOv8在禾本科杂草目标检测方面有显著的应用和效果。以下是一些关键信息的总结&#xff1a; 农作物幼苗与杂草检测系统&#xff1a;基于YOLOv8深度学习框架&#xff0c;通过2822张图片训练了一个目标检测模型&#xff…

比亚迪夏直插家用MPV腹地,“迪王”开启全面销冠新征程

文/王俣祺 导语&#xff1a;比亚迪前脚刚收获2024年的全面成功&#xff0c;后脚立刻就开始布局2025年的产品矩阵了。比亚迪夏的横空出世&#xff0c;看来家用MPV市场也要感受“迪王”的恐怖如斯了。 家用MPV市场的“意外之喜” 1月8日&#xff0c;比亚迪夏终于在万众瞩目之下…