从一个小故事讲解观察者模式~
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
什么是观察者模式?
观察者模式在我们的日常生活中极其常见。
先来看看观察者模式的定义:
观察者模式定义了对象之间一对多的依赖,当这样一来,当一个对象状态改变时,它的所有依赖者都会收到通知并自动更新。
这个模式在我们日常生活中可以说是太常见了!
比如手机上的天气预报,一旦气象局的信息进行了更新,手机上的天气信息就会相应的变化;
比如10086群发的消息,其实也是一个观察者模式的例子,每当10086发送一条消息时,所有的移动手机都会收到这个消息。而且一般消息中都会附带一个提醒“退订请回复T”,一旦回复了T,以后就不会接收到显10086对应的短信了。
比如麦当劳吃炸鸡时,当一份食物准备好,就会通知“3045、3045、3045”请取餐,大家都能听到,但是可能只有一个人会去取餐,因为订阅者可以自行决定接收到消息之后动不动,或者说做什么;又比如…
观察者模式描述的就是订阅者和发布者之间的联系。其UML类图如下:

在这个下面给出订阅者和发布者的一个例子。
应用实例
借鉴《大话设计模式》的看门放哨的例子,我们来设计这样一个场景:
“一堂自习课时,小红、小蓝、小绿三人无心学习,各玩各的。坐在门口小黄在门口放哨,一旦看到班主任的身影,就敲一下桌子,其他三人应声而动,赶忙拿出书进行学习。当班主任走远了,小黄敲两下桌子,大家又开始愉快的玩耍…”
- 主体接口
主体接口,又称为被观察者,采用接口的方式可以给具体的主体类实现自己的逻辑,如采用链表、数组、或者Map等结构存储观察者。
public interface Subject {// 增加观察者public void attach(Observer observer);// 删除观察者public void detach(Observer observer);// 通知所有观察者public void notifyObservers();// 主体(被观察者)状态public void setAction(String action);public String getAction();
}
- 通知者接口
通知者接口主要是定义了一个接口,不同的通知者实现自己的消息逻辑:
public abstract class Observer {protected String name;protected Subject subject;public Observer(String name, Subject subject) {this.name = name;this.subject = subject;}public abstract void update();
}
- 实际观察者(小红、小蓝、小绿)
分别实现三个同学:
public class Xiaohong extends Observer {public Xiaohong(String name, Subject subject) {super(name, subject);}@Overridepublic void update() {System.out.println(subject.getAction() + "\n" + name + "把小说藏起来!继续学习!");}
}
public class Xiaolan extends Observer {public Xiaolan(String name, Subject subject) {super(name, subject);}@Overridepublic void update() {System.out.println(subject.getAction() + "\n" + name + "把手机收起来!继续学习!");}
}
public class Xiaolv extends Observer {public Xiaolv(String name, Subject subject) {super(name, subject);}@Overridepublic void update() {System.out.println(subject.getAction() + "\n" + name + "把游戏机收起来!继续学习!");}
}
- 实际发布者(小黄)
小黄观察老师的到来,通知大家:
public class Xiaohuang implements Subject {// 需要通知的同学列表private final List<Observer> observers = new LinkedList<>();private String action;// 添加通知同学@Overridepublic void attach(Observer observer) {observers.add(observer);}// 删除通知同学@Overridepublic void detach(Observer observer) {observers.remove(observer);}// 通知所有同学@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update();}}// 获取通知状态@Overridepublic String getAction() {return action;}// 设置通知状态@Overridepublic void setAction(String action) {this.action = action;}
}
- 运行客户端
public class App {public static void main(String[] args) {// 前台为通知者Xiaohuang xiaohuang = new Xiaohuang();Xiaohong observer1 = new Xiaohong("小红", xiaohuang);Xiaolv observer2 = new Xiaolv("小绿", xiaohuang);Xiaolan observer3 = new Xiaolan("小蓝", xiaohuang);// 需要通知三个xiaohuang.attach(observer1);xiaohuang.attach(observer2);xiaohuang.attach(observer3);// 设置通知状态xiaohuang.setAction("小心!Boss回来了!");// 发送通知xiaohuang.notifyObservers();}
}
结果如下:

总结
优点
- 观察者模式实现了发布者和订阅者之间的松耦合:两个对象之间可以进行交互,但是不太清楚彼此之间的细节;
- 适用于一个对象改变,相联系的对象随之发生相应变化的场景。
缺点
- 如果对象之间有循环依赖,在观察者模式下可能会引发循环调用,从而造成系统崩溃;
总而言之,当对象之间的关系类似与消息群发这样的一对多关系时,就可以开始考虑用不用观察者模式了。(都这个时候了,不用它还能用谁啊?)
参考资料
《Head First 设计模式》
《大话设计模式》
观察者模式——极客教程
相关文章:
从一个小故事讲解观察者模式~
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 什么是观察者模式? 观察者模式在我们的日常生活中极其常见。 先来看看观察者模式的定义: 观察者模式定义了对象之间…...
LeetCode、1137. 第 N 个泰波那契数【简单,动态规划】
文章目录 前言LeetCode、1137. 第 N 个泰波那契数【简单,动态规划】题目与分类思路一维动态规划 资料获取 前言 博主介绍:✌目前全网粉丝2W,csdn博客专家、Java领域优质创作者,博客之星、阿里云平台优质作者、专注于Java后端技术…...
Python爬虫urllib详解
前言 学习爬虫,最初的操作便是模拟浏览器向服务器发出请求,那么我们需要从哪个地方做起呢?请求需要我们自己来构造吗?需要关心请求这个数据结构的实现吗?需要了解 HTTP、TCP、IP 层的网络传输通信吗?需要知…...
Linux嵌入式开发+驱动开发-中断
swi汇编指令可以产生软中断,以下是硬件中断的产生到执行完毕的全过程: 在自己设计的芯片“CPU响应中断”程序的第四个步骤可以转向“中断向量控制器”,中断向量控制器中存储中断元服务地址即处理中断处理程序的地址,而不用使用0X1…...
android tv开发-1,leanback
目录 1.leanback库的一些事 2.leanback在使用时遇到的一些麻烦 视频卡片 页面空白 关于左侧菜单的一些设置 数据加载异常与加载中的一些操作 如果页面无数据,如何显示错误的页面....
chisel RegInit/UInt/U
val reg RegInit(0.U(8.W)) //ok val reg RegInit(0.UInt(8.W)) //errU 使用在数字 . 后边50.U UInt 使用在IO(new Bundle val a Input(UInt(8.W)) 或者 def counter(max:UInt, a1:UInt) package emptyimport chisel3._ import chisel3.util._class MyCounter extends …...
华为OD机试真题-田忌赛马-2024年OD统一考试(C卷)
题目: 给定两个只包含数字的数组a,b,调整数组 a 里面数字的顺序,使得尽可能多的 a[i] >b[i]。数组 a和 b 中的数字各不相同。 输出所有可以达到最优结果的 a 数组的数量 输入描述: 输入的第一行是数组 a 中的数字,其中只包含数字,每两个数字之间相隔一个空格,a 数组…...
QMUI_Android:提升Android开发效率与质量的利器
QMUI_Android:提升Android开发效率与质量的利器 在Android应用开发过程中,开发者常常面临着重复编写基础组件和处理兼容性问题的挑战,这不仅耗费时间,也降低了开发效率。为了解决这一问题,Tencent推出了QMUI_Android框…...
如何部署Linux AMH服务器管理面板并结合内网穿透远程访问
文章目录 1. Linux 安装AMH 面板2. 本地访问AMH 面板3. Linux安装Cpolar4. 配置AMH面板公网地址5. 远程访问AMH面板6. 固定AMH面板公网地址 AMH 是一款基于 Linux 系统的服务器管理面板,它提供了一系列的功能,包括网站管理、FTP 管理、数据库管理、DNS 管…...
C++文件操作(2)
文件操作(2) 1.二进制模式读取文本文件2.使用二进制读写其他类型内容3.fstream类4.文件的随机存取文件指针的获取文件指针的移动 1.二进制模式读取文本文件 用二进制方式打开文本存储的文件时,也可以读取其中的内容,因为文本文件…...
Bootstrap5 图片轮播
Bootstrap5 轮播样式表使用的是CDN资源 <title>亚丁号</title><!-- 自定义样式表 --><link href"static/front/css/front.css" rel"stylesheet" /><!-- 新 Bootstrap5 核心 CSS 文件 --><link rel"stylesheet"…...
WINDOWS搭建NFS服务器
下载并安装 Networking Software for Windows 启动配置 找到安装目录(如C:\Program Files\nfsd),双击nfsctl.exe,菜单Edit->Preferences 启动后: 配置Export Exports->Edit exports file 其他的几句我都删除…...
LeetCode、216. 组合总和 III【中等,组合型枚举】
文章目录 前言LeetCode、216. 组合总和 III【中等,组合型枚举】题目类型与分类思路 资料获取 前言 博主介绍:✌目前全网粉丝2W,csdn博客专家、Java领域优质创作者,博客之星、阿里云平台优质作者、专注于Java后端技术领域。 涵盖…...
支持534种语言,开源大语言模型MaLA-500
无论是开源的LLaMA 2还是闭源的GPT系列模型,功能虽然很强大,但对语言的支持和扩展比较差,例如,二者都是以英语为主的大模型。 为了提升大模型语言的多元化,慕尼黑大学、赫尔辛基大学等研究人员联合开源了,…...
面试 JavaScript 框架八股文十问十答第一期
面试 JavaScript 框架八股文十问十答第一期 作者:程序员小白条,个人博客 相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新! ⭐点赞⭐收藏⭐不迷路!⭐ 1)JavaScript有哪些…...
【发票识别】新增针对图片发票的识别(升级中)
说明 为了完善发票识别的功能,目前发票识别支持发票图片格式的识别,增加可用性。 体验 体验地址:https://invoice.behappyto.cn/invoice-service/ 体验地址上面有示例的发票,可以下载上传识别或者复制url地址进行识别。 技术栈…...
面试数据结构与算法总结分类+leetcode目录【基础版】
🧡🧡🧡算法题目总结: 这里为大家总结数据结构与算法的题库目录,如果已经解释过的题目会标注链接更新,方便查看。 数据结构概览 Array & String 大家对这两类肯定比较清楚的,同时这也是面试…...
音频二维码怎么制作出来的?支持多种格式音频生码的方法
怎么把一个音频的文件做成二维码图片呢?在日常工作和生活中,有很多的场景会需要使用音频类型的文件来展示内容,比如常见的英语听力、课程、听书等类型的内容,现在都可以用二维码展示。而且现在生成音频二维码的方法也很简单&#…...
ReactNative实现一个圆环进度条
我们直接看效果,如下图 我们在直接上代码 /*** 圆形进度条*/ import React, {useState, useEffect} from react; import Svg, {Circle,G,LinearGradient,Stop,Defs,Text, } from react-native-svg; import {View, StyleSheet} from react-native;// 渐变色 const C…...
【JS逆向学习】今日头条
逆向目标 目标网页:https://www.toutiao.com/?wid1707099375036目标接口:https://www.toutiao.com/api/pc/list/feed目标参数:_signature 逆向过程 老规矩先观察网络请求,过滤XHR请求观察加密参数,发现Payload的_s…...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
MySQL 主从同步异常处理
阅读原文:https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主,遇到的这个错误: Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一,通常表示ÿ…...
