当前位置: 首页 > news >正文

【设计模式】详解观察者模式

文章目录

  • 1、简介
  • 2、观察者模式简单实现
    • 抽象主题(Subject)
    • 具体主题(ConcreteSubject)
    • 抽象观察者(Observer)
    • 具体观察者(ConcrereObserver)
    • 测试:
  • 观察者设计模式优缺点
    • 观察者模式的优点包括:
    • 观察者模式的缺点包括:

1、简介

观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,它的所有依赖者都会收到通知并自动更新。(MQ和它有点像)
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。
在这里插入图片描述
观察者模式中,一共有四种角色:

  1. Subject(抽象主题):也称为被观察者或可观察者,它是具有状态的对象,并维护着一个观察者列表。抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者。主题提供了添加、删除和通知观察者的方法。一般用一个抽象类或者一个接口实现
  2. Observer(抽象观察者):为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者角色一般用一个抽象类或者一个接口实现。在这个示意性的实现中,更新接口只包含一个方法(即Update()方法),这个方法叫做更新方法。
  3. ConcreteSubject(具体主题):也可称为具体被观察者,该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
  4. ConcrereObserver(具体观察者):实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。如果需要,具体现察者角色可以保存一个指向具体主题对象的引用。

从具体主题角色指向抽象观察者角色的合成关系,代表具体主题对象可以有任意多个对抽象观察者对象的引用。之所以使用抽象观察者而不是具体观察者,意味着主题对象不需要知道引用了哪些ConcreteObserver类型,而只知道抽象Observer类型。这就使得具体主题对象可以动态地维护一系列的对观察者对象的引用,并在需要通知的时候调用每一个观察者共有的update()更新方法。这种做法叫做"针对抽象编程"。

2、观察者模式简单实现

拿博客专栏订阅为例,网站用户的博客专栏为被观察者,用户为观察者,当有多个用户关注了yhz的JVM专栏,当yhz的JVM专栏更新时就会通知这些订阅的用户。

抽象主题(Subject)

package DesignModel.Observer;import java.util.ArrayList;/*** @BelongsProject: 3.9.demo* @Author: yhz* @CreateTime: 2023-07-26  17:58* @Description: TODO* @Version: 1.0*/
public abstract class Subject {//定义一个订阅者集合用于存储所有订阅了这个专栏的用户对象protected ArrayList<Observer>observers = new ArrayList();//注册方法,用于向订阅者集合中增加一个订阅者public void attach( Observer observer ) {observers.add( observer );}//注销方法,用于在订阅者集合中删除一个订阅者public void detach( Observer observer ) {observers.remove( observer );}//通知所有订阅者更新消息public abstract void notifyObservers(String message);
}

具体主题(ConcreteSubject)

yhz的这个专栏为具体主题,里面存储了订阅该专栏的网站用户,并实现了抽象主题中的通知方法:

package DesignModel.Observer;/*** @BelongsProject: 3.9.demo* @Author: yhz* @CreateTime: 2023-07-26  18:18* @Description: TODO* @Version: 1.0*/
public class ConcreteSubject extends Subject{//重写通知方法为自己的@Overridepublic void notifyObservers(String message) {//通知订阅了该主题的所有订阅者for(Observer observer:observers){observer.update(message);}}
}

抽象观察者(Observer)

package DesignModel.Observer;public interface Observer {//声明了更i性能方法void update(String message);
}

具体观察者(ConcrereObserver)

网站用户作为具体观察者,里面实现了更新的方法

package DesignModel.Observer;/*** @BelongsProject: 3.9.demo* @Author: yhz* @CreateTime: 2023-07-26  18:06* @Description: TODO* @Version: 1.0*/
public class Blooger implements Observer{//博主名称private String bloogerName;public Blooger(String bloogerName) {this.bloogerName = bloogerName;}@Overridepublic void update(String message) {System.out.println(bloogerName+message);}
}

测试:

package DesignModel.Observer;/*** @BelongsProject: 3.9.demo* @Author: yhz* @CreateTime: 2023-07-26  18:21* @Description: TODO* @Version: 1.0*/
public class Test {public static void main(String[] args) {ConcreteSubject subject = new ConcreteSubject();Blooger blooger = new Blooger("aa1");Blooger blooger2 = new Blooger("aa2");Blooger blooger3 = new Blooger("aa3");Blooger blooger4 = new Blooger("aa4");subject.attach(blooger);subject.attach(blooger2);subject.attach(blooger3);subject.attach(blooger4);subject.notifyObservers("您关注的yhz更新了博客");}
}

结果打印:

aa1您关注的yhz更新了博客
aa2您关注的yhz更新了博客
aa3您关注的yhz更新了博客
aa4您关注的yhz更新了博客

观察者设计模式优缺点

观察者模式的优点包括:

  • 降低了主题与观察者之间的耦合关系,两者之间是抽象耦合关系。可以很容易扩展观察者和被观察者。
  • 主题与观察者之间建立了一套触发机制。

观察者模式的缺点包括:

  • 主题与观察者之间的依赖关系并没有完全解除。
  • 当观察者对象很多时,通知的发布会花费很长时间,影响程序效率。
  • 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
  • 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。

在使用观察者模式时,需要谨慎处理这些问题,以确保系统的稳定性和效率。

相关文章:

【设计模式】详解观察者模式

文章目录 1、简介2、观察者模式简单实现抽象主题&#xff08;Subject&#xff09;具体主题&#xff08;ConcreteSubject&#xff09;抽象观察者&#xff08;Observer&#xff09;具体观察者&#xff08;ConcrereObserver&#xff09;测试&#xff1a; 观察者设计模式优缺点观察…...

用html+javascript打造公文一键排版系统8:附件及标题排版

最近工作有点忙&#xff0c;所 以没能及时完善公文一键排版系统&#xff0c;现在只好熬夜更新一下。 有时公文有包括附件&#xff0c;招照公文排版规范&#xff1a; 附件应当另面编排&#xff0c;并在版记之前&#xff0c;与公文正文一起装订。“附件”二字及附件顺序号用3号黑…...

微服务体系<1>

我们的微服务架构 我们的微服务架构和单体架构的区别 什么是微服务架构 微服务就是吧我们传统的单体服务分成 订单模块 库存模块 账户模块单体模块 是本地调用 从订单模块 调用到库存模块 再到账户模块 这三个模块都是调用的同一个数据库 这就是我们的单体架构微服务 就是…...

M5ATOMS3基础02传感器MPU6886

M5ATOMS3基础01按键 简洁版本 MPU6886是一款6轴IMU单元&#xff0c;具有3轴重力加速度计和3轴陀螺仪。它采用16位ADC&#xff0c;内置可编程数字滤波器和片上温度传感器&#xff0c;并通过I2C接口&#xff08;地址为0x68&#xff09;与上位机通信。MPU6886支持低功耗模式&#…...

vue 快速自定义分页el-pagination

vue 快速自定义分页el-pagination template <div style"text-align: center"><el-paginationbackground:current-page"pageObj.currentPage":page-size"pageObj.page":page-sizes"pageObj.pageSize"layout"total,prev,…...

0-虚拟机补充知识

虚拟机克隆 如果想要构建服务器集群&#xff0c;没有必要一台一台的去进行安装&#xff0c;只要通过克隆就可以。 快速获得多台服务器主要有两种方式&#xff0c;分别为&#xff1a;直接拷贝操作和vmware的克隆操作 直接拷贝 将之前安装虚拟机的所有文件进行拷贝&#xff0…...

如何将电机控制器添加到您的 ROS 机器人

一、说明 如果您正在构建与 ROS/ROS2 一起使用的移动机器人,您需要做的第一件事就是集成电机控制器。电机控制器的目的是接受来自更高级别的软件(如导航堆栈)的消息,并将其转换为驱动电机的信号。它还将从电机的编码器接收信息,以计算机器人的速度和位置。 您可以…...

ChatGPT统计“一到点就下班”的人数

ChatGPT统计“一到点就下班”的人数 1、到点下班 Chatgpt统计各部门F-D级员工到点下班人数占比&#xff0c;是在批评公司内部存在到点下班现象。 根据图片&#xff0c;该占比的计算方法是&#xff1a;最后一次下班卡在17:30-17:40之间&#xff0c;且1-5月合计有40天以上的人…...

Games101学习笔记 - 变换矩阵基础

二维空间下的变换 缩放矩阵 缩放变换: 假如一个点&#xff08;X,Y&#xff09;。x经过n倍缩放&#xff0c;y经过m倍缩放&#xff0c;得到的新点&#xff08;X1&#xff0c;Y1&#xff09;&#xff1b;那么新点和远点有如下关系&#xff0c;X1 n*X, Y1 m*Y写成矩阵就是如下…...

Ubuntu18.04未安装Qt报qt.qpa.plugin could not load the Qt platform plugin xcb问题的解决方法

在Ubuntu 18.04开发机上安装了Qt 5.14.2&#xff0c;当将其可执行程序拷贝到另一台未安装Qt的Ubuntu 18.04上报错&#xff1a;拷贝可执行程序前&#xff0c;使用ldd将此执行程序依赖的动态库也一起拷贝过去&#xff0c;包括Qt5.14.2/5.14.2/gcc_64/plugins目录系的platforms目录…...

GPT4ALL私有化部署 01 | Python环境

进入以下链接&#xff1a; https://www.python.org/downloads/release/python-3100/ 滑动到底部 选择你系统对应的版本&#xff0c;如果你是win&#xff0c;那么大概率是win-64bit 有可能你会因为网络的问题导致下载不了&#xff0c;我提供了 链接 接着只需要打开 等待…...

GPT-AI 使用的技术概览

ChatGPT 使用的技术概览 智心AI-3.5/4模型&#xff0c;联网对话&#xff0c;MJ快速绘画 从去年 OpenAI 发布 ChatGPT 以来&#xff0c;AI 的能力再次惊艳了世人。在这样的一个时间节点&#xff0c;重新去学习相关技术显得很有必要。 ChatGPT 的内容很多&#xff0c;我计划采用…...

NoSQL-Redis持久化

NoSQL-Redis持久化 一、Redis 高可用&#xff1a;1.概述&#xff1a; 二、Redis持久化&#xff1a;1.持久化的功能&#xff1a;2.Redis 提供两种方式进行持久化&#xff1a; 三、RDB 持久化&#xff1a;1.定义&#xff1a;2.触发条件&#xff1a;3.执行流程&#xff1a;4.启动时…...

关于uniapp中的日历组件uni-calendar中的小红点

关于uniapp中的日历组件uni-calendar中的小红点 如果你使用过uni-calendar组件&#xff0c;可能你觉得这个小红点有点碍眼&#xff0c;但是官方给定的日历组件uni-calendar中如果你想要在某一天上添加一些信息例如:价格&#xff0c;签到&#xff0c;打卡之类&#xff0c;只要标…...

【Nodejs】Node.js简介

1.前言 Node 的重要性已经不言而喻&#xff0c;很多互联网公司都已经有大量的高性能系统运行在 Node 之上。Node 凭借其单线程、异步等举措实现了极高的性能基准。此外&#xff0c;目前最为流行的 Web 开发模式是前后端分离的形式&#xff0c;即前端开发者与后端开发者在自己喜…...

SpringBoot整合Druid

在Spring Boot中整合Druid时&#xff0c;需要导入Druid和JDBC的相关依赖&#xff0c;但不需要额外导入单独的JDBC包。 Druid是一个用于数据库连接池和监控的开源框架&#xff0c;它已经包含了对JDBC的实现。因此&#xff0c;当你导入Druid的依赖时&#xff0c;它已经包含了对J…...

mysql(二)SQL语句

目录 一、SQL语句类型 二、数据库操作 三、数据类型 四、创建 五、查看 六、更改 七、增、删、改、查 八、查询数据 一、SQL语句类型 SQL语句类型&#xff1a; DDL DDL&#xff08;Data Definition Language&#xff0c;数据定义语言&#xff09;&#xff1a;用于…...

Unity自定义后处理——Tonemapping色调映射

大家好&#xff0c;我是阿赵。   继续介绍屏幕后处理&#xff0c;这一期介绍一下Tonemapping色调映射 一、Tone Mapping的介绍 Tone Mapping色调映射&#xff0c;是一种颜色的映射关系处理&#xff0c;简单一点说&#xff0c;一般是从原始色调&#xff08;通常是高动态范围&…...

Redis学习 知识总结 一

Redis学习 知识总结 一 1 Redis初识1.1 Redis八大特性1.2 redis使用场景1.3 Docker安装redis 2 API的理解和使用2.1 通用命令2.2 字符串&#xff08;String&#xff09;类型2.3 哈希&#xff08;Hash&#xff09;类型2.4 有序列表&#xff08;list&#xff09;2.5 集合&#xf…...

Webpack5 vue-loader和VueLoaderPlugin

文章目录 vue-loader和VueLoaderPlugin的作用vue-loader具体使用方式注意事项 vue-loader和VueLoaderPlugin的作用 .vue 文件是用户用 HTML-like 的语法编写的 Vue 组件。每个vue 文件都包括三部分 , VueLoaderPlugin 是一个解析 Vue.js 的插件&#xff0c;用于在 webpack 构…...

零代码上手MGeo地址匹配:5分钟部署,实测中文地址识别准确率92.7%

零代码上手MGeo地址匹配&#xff1a;5分钟部署&#xff0c;实测中文地址识别准确率92.7% 地址匹配一直是中文NLP领域的难题——"北京市朝阳区建国路88号"和"朝阳区建国路88号大望中心"&#xff0c;人类一眼就能判断是同一地点&#xff0c;但传统方法却束手…...

从零到一:用JavaScript在Screeps Arena中构建你的首个RTS AI

1. 初识Screeps Arena&#xff1a;编程与策略的完美结合 Screeps Arena是一款独特的编程策略游戏&#xff0c;它将即时战略&#xff08;RTS&#xff09;的核心玩法与JavaScript编程完美融合。与传统RTS游戏不同&#xff0c;在这里你不是通过鼠标点击来指挥单位&#xff0c;而是…...

【CAPL实战】LIN校验和自动化测试:从函数解析到脚本验证

1. LIN校验和的核心概念与CAPL函数解析 第一次接触LIN总线校验和测试时&#xff0c;我也曾被各种专业术语绕得头晕。简单来说&#xff0c;校验和就像是给数据包贴上的"防伪标签"——当LIN报文从主机发往从机时&#xff0c;这个标签能帮我们确认数据在传输过程中是否…...

Intv_ai_mk11 Java开发指南:从环境配置到第一个对话应用

Intv_ai_mk11 Java开发指南&#xff1a;从环境配置到第一个对话应用 1. 开篇&#xff1a;为什么Java开发者需要关注AI 如果你是一名Java开发者&#xff0c;可能已经注意到AI技术正在改变软件开发的格局。传统业务系统与AI能力的结合&#xff0c;正在创造全新的应用场景。Intv…...

Fluvio Connectors 终极指南:5步快速构建实时数据管道

Fluvio Connectors 终极指南&#xff1a;5步快速构建实时数据管道 【免费下载链接】fluvio &#x1f980; event stream processing for developers to collect and transform data in motion to power responsive data intensive applications. 项目地址: https://gitcode.c…...

Linux平台总线驱动开发与设备树应用详解

1. Linux总线设备驱动模型概述在Linux内核开发中&#xff0c;总线设备驱动模型是一个非常重要的架构设计。作为一名长期从事Linux驱动开发的工程师&#xff0c;我深刻体会到这种设计模式带来的好处。它完美体现了软件工程中的"分离"思想&#xff0c;让驱动开发变得更…...

Qwen3.5推理模型效果实测:分步骤解题、结构化分析惊艳展示

Qwen3.5推理模型效果实测&#xff1a;分步骤解题、结构化分析惊艳展示 1. 模型核心能力概览 Qwen3.5-4B-Claude-4.6-Opus-Reasoning-Distilled-GGUF作为一款专精推理的蒸馏模型&#xff0c;在结构化问题解决方面展现出独特优势。经过实测&#xff0c;其核心能力可归纳为三个维…...

城通网盘直链解析:三步实现免费高速下载的完整方案

城通网盘直链解析&#xff1a;三步实现免费高速下载的完整方案 【免费下载链接】ctfileGet 获取城通网盘一次性直连地址 项目地址: https://gitcode.com/gh_mirrors/ct/ctfileGet 还在为网盘下载速度慢而烦恼吗&#xff1f;ctfileGet为你提供了一个智能解决方案&#xf…...

Arduino MKR IoT Carrier 库底层控制与工程实践指南

1. Arduino MKR IoT Carrier 库深度解析&#xff1a;面向嵌入式工程师的底层控制指南 Arduino MKR IoT Carrier 是专为 MKR 系列开发板&#xff08;如 MKR WiFi 1010、MKR NB 1500、MKR GSM 1400 等&#xff09;设计的硬件抽象层库&#xff0c;其核心目标并非提供通用传感器驱…...

Entries()方法

entries() 方法返回一个迭代器对象&#xff0c;包含数据结构中每个元素的键值对。不同数据结构的用法略有不同。1. 数组的 entries()返回索引和值的键值对const arr [a, b, c]; const iterator arr.entries();console.log(iterator.next().value); // [0, a] console.log(ite…...