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

观察者模式:对象之间的订阅机制

欢迎来到设计模式系列的第十三篇文章!在之前的文章中,我们学习了许多常用的设计模式,今天我们将介绍观察者模式,它是一种行为型设计模式,用于定义对象之间的一对多依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。

在学习观察者模式前,我们可以带着一下三个问题来学习:

1.谁是观察者,谁又是被观察者?

2.观察者如何”观察”被观察者的?

3.为什么要使用观察着模式?

4.你在工作中见过哪些观察者模式?

观察者模式简介

观察者模式是一种常用的设计模式,它用于构建对象之间的发布-订阅(Publish-Subscribe)关系。在观察者模式中,有两类核心角色:

  • 主题(Subject):主题是被观察的对象,它维护了一个观察者列表,可以动态地添加或删除观察者。主题通常具有一种状态,当状态发生变化时,会通知所有观察者。
  • 观察者(Observer):观察者是依赖于主题的对象,它们会注册到主题上,以便在主题的状态发生变化时得到通知并执行相应的操作。

观察者模式的核心思想是降低主题和观察者之间的耦合度,使得它们可以独立地变化。这种松耦合的设计可以更好地支持可维护性和可扩展性。

为什么需要观察者模式?

在软件开发中,经常会遇到一对多的场景,例如:

  • 一个新闻网站需要通知多个订阅者(用户)有新文章发布。
  • 一个股票市场应用需要通知多个投资者股票价格的变化。
  • 一个气象站需要通知多个应用天气信息的变化。

如果没有观察者模式,我们可能会采用硬编码的方式来实现这些通知,但这样会导致高耦合和不易维护的问题。观察者模式通过将主题和观察者分离,使得它们可以独立变化,从而更好地应对这类场景。

观察者模式的实现

观察者模式的实现通常包括以下几个关键元素:

  1. 主题接口(Subject):定义了主题对象的基本操作,包括注册观察者、删除观察者和通知观察者等。
  2. 具体主题(ConcreteSubject):实现了主题接口,并维护了一个观察者列表。具体主题通常具有一个状态,当状态发生变化时,会通知所有注册的观察者。
  3. 观察者接口(Observer):定义了观察者对象的更新操作,通常包括一个 update 方法。
  4. 具体观察者(ConcreteObserver):实现了观察者接口,并注册到具体主题上。当主题状态发生变化时,具体观察者的 update 方法会被调用。

现在,让我们通过一个示例来演示观察者模式的实现。假设我们正在开发一个简单的股票市场应用,股票价格会不断变化,我们需要通知多个投资者股票价格的变化情况。

首先,我们定义观察者接口 Observer

public interface Observer {void update(double price);
}

然后,我们定义主题接口 Subject

public interface Subject {void registerObserver(Observer observer);void removeObserver(Observer observer);void notifyObservers();
}

接下来,我们创建一个具体主题 StockMarket,它继承了 Subject 接口:

import java.util.ArrayList;
import java.util.List;public class StockMarket implements Subject {private List<Observer> observers = new ArrayList<>();private double price;@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(price);}}public void setPrice(double price) {this.price = price;notifyObservers();}
}

StockMarket 类中,我们维护了一个观察者列表 observers 和股票价格 price。当 setPrice 方法被调用时,会通知所有注册的观察者。

接下来,我们创建一个具体观察者 Investor,它实现了 Observer 接口:

public class Investor implements Observer {private String name;public Investor(String name) {this.name = name;}@Overridepublic void update(double price) {System.out.println(name + " 收到股票价格更新,当前价格为 " + price);}
}

最后,我们可以测试观察者模式的效果:

public class Main {public static void main(String[] args) {StockMarket stockMarket = new StockMarket();Investor investor1 = new Investor("Alice");Investor investor2 = new Investor("Bob");stockMarket.registerObserver(investor1);stockMarket.registerObserver(investor2);stockMarket.setPrice(100.0);stockMarket.setPrice(105.0);stockMarket.removeObserver(investor1);stockMarket.setPrice(110.0);}
}

以上代码创建了一个股票市场 StockMarket 和两个投资者 Investor,并演示了股票价格的变化如何通知投资者。

观察者模式的优点

观察者模式具有许多优点,使其成为软件开发中常用的设计模式之一:

  1. 降低耦合度:观察者模式将主题和观察者分离,主题不需要知道观察者的具体细节,从而降低了它们之间的耦合度。
  2. 支持广播通信:主题状态变化时,可以通知多个观察者,实现了一对多的通信,方便信息广播。
  3. 开闭原则:通过增加新的观察者类和主题类,可以扩展观察者模式,符合开闭原则。
  4. 可维护性:因为观察者和主题之间的关系是松散的,所以更容易维护和修改。

观察者模式的缺点

观察者模式也存在一些缺点,需要考虑:

  1. 观察者太多时性能问题:如果观察者太多,通知所有观察者可能会影响性能,尤其是在大规模系统中。
  2. 顺序问题:观察者的通知顺序可能不确定,如果有顺序要求,需要额外处理。
  3. 可能导致循环依赖:主题和观察者之间的循环依赖可能引入问题,需要小心处理。

观察者模式的应用场景

观察者模式适用于以下场景:

  1. 一对多的依赖关系:当一个对象的状态变化需要通知多个其他对象时,观察者模式非常适用。例如,新闻发布、股票市场更新等。
  2. 抽象模型与实现分离:当需要将抽象模型与其具体实现分离时,观察者模式可以帮助实现这种分离。例如,图形界面框架中的事件处理。
  3. 动态系统:在动态系统中,对象的数量和类型可能会随时改变,观察者模式允许动态地添加或删除观察者。

观察者模式的实际应用

观察者模式在现实世界和软件开发中都有广泛应用。以下是一些实际应用示例:

  1. 邮件订阅:邮件订阅服务是观察者模式的一个典型应用。用户可以订阅不同类型的邮件通知,当有新邮件到达时,订阅者会收到通知。
  2. 社交媒体通知:社交媒体平台可以通知用户关注的人或页面的更新,例如,新的帖子、消息或评论。
  3. 股票市场应用:股票市场应用通常使用观察者模式来实时通知投资者股票价格的变化。
  4. 事件处理:图形用户界面(GUI)框架使用观察者模式来处理用户事件,例如,鼠标点击、键盘输入等。

最佳实践

在使用观察者模式时,有一些最佳实践值得注意:

  1. 避免循环依赖:确保主题和观察者之间没有循环依赖,以防止潜在的问题。
  2. 考虑多线程情况:如果在多线程环境中使用观察者模式,确保实现线程安全的方式来处理观察者列表和状态更新。
  3. 谨慎使用广播通知:通知所有观察者可能会影响性能,如果只有部分观察者关心状态变化,可以考虑使用条件通知。

想进一步了解观察者模式的老铁可以了解一下 spring中的事件机制:深入理解事件发布监听机制

总结

观察者模式是一种非常有用的设计模式,用于实现对象之间的松耦合通信。通过定义一对多的依赖关系,主题状态变化时通知多个观察者,实现了对象之间的订阅机制。在实际应用中,观察者模式可以帮助我们构建灵活、可扩展的系统。

相关文章:

观察者模式:对象之间的订阅机制

欢迎来到设计模式系列的第十三篇文章&#xff01;在之前的文章中&#xff0c;我们学习了许多常用的设计模式&#xff0c;今天我们将介绍观察者模式&#xff0c;它是一种行为型设计模式&#xff0c;用于定义对象之间的一对多依赖关系&#xff0c;当一个对象的状态发生变化时&…...

【1462. 课程表 IV】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 你总共需要上 numCourses 门课&#xff0c;课程编号依次为 0 到 numCourses-1 。你会得到一个数组 prerequisite &#xff0c;其中 prerequisites[i] [ai, bi] 表示如果你想选 bi 课程&#xff0c;你…...

Kerberos 身份验证

简介 Kerberos 是一种由 MIT&#xff08;麻省理工大学&#xff09;提出的一种基于加密 Ticket 的身份认证协议。它旨在通过使用密钥加密技术为客户端/服务器应用程序提供强身份验证&#xff0c;用于验证用户或主机的标识。。 适用范围&#xff1a;Windows Server 2022、Window…...

R语言贝叶斯METROPOLIS-HASTINGS GIBBS 吉布斯采样器估计变点指数分布分析泊松过程车站等待时间...

原文链接&#xff1a;http://tecdat.cn/?p26578 指数分布是泊松过程中事件之间时间的概率分布&#xff0c;因此它用于预测到下一个事件的等待时间&#xff0c;例如&#xff0c;您需要在公共汽车站等待的时间&#xff0c;直到下一班车到了&#xff08;点击文末“阅读原文”获取…...

通付盾入选2023年度“上市苗圃工程”重点企业

近日&#xff0c;2023年度苏州工业园区企业上市苗圃工程认定名单公示&#xff0c;江苏通付盾科技有限公司成功入选园区“上市苗圃工程”重点企业。 2023年第一批次苗圃企业认定结果&#xff1a; 企业上市苗圃工程 上市企业是衡量地方综合经济实力的重要标尺&#xff0c;也是区…...

SpringMVC之文件上传下载

SpringMVC是一个基于Java的Web框架&#xff0c;它提供了一套用于构建Web应用程序的开发模型。在SpringMVC中&#xff0c;文件上传和下载是常见的功能之一。 SpringMVC文件上传和下载的介绍&#xff1a; 介绍文件上传&#xff1a; 在SpringMVC中&#xff0c;文件上传功能可以通…...

嵌入式IDE(2):KEIL中SCF分散加载链接文件详解和实例分析

在上一篇文章IAR中ICF链接文件详解和实例分析中&#xff0c;我通过I.MX RT1170的SDK中的内存映射关系&#xff0c;分析了IAR中的ICF链接文件的语法。对于MCU编程所使用的IDE来说&#xff0c;IAR和Keil用得比较多&#xff0c;所以这一篇文章就来分析一下Keil的分散文件.scf(scat…...

Linux防火墙常用操作及端口开放

Linux防火墙常用操作及端口开放 1.查看防火墙状态 firewall-cmd --state 2.开启防火墙 systemctl start firewalld.service 3.开启指定端口 firewall-cmd --zonepublic --add-port3306/tcp --permanent firewall-cmd --zonepublic --add-port6379/tcp --permanent 显示success表…...

[JAVAee]Linux上的javax.mail报错

我们把在window写的项目部署到Linux上的Tomcat时,如果发现使用不了了,该如何找到错误呢?找到报错的地方在哪呢? 在Linux环境下来到Tomcat目录下的logs目录,输入: tail -f catalina.out -n 500 tail 就是把文件的末尾几行读取到终端上,并会持续刷新 -f 循环读取 catalina.ou…...

开学季|校园迎新哪家强?VR全景来导航

九月开学迎新季&#xff0c;各大高校的迎新活动开展的如火如荼&#xff0c;随着科技的不断进步&#xff0c;高校为了更好的开展迎新活动&#xff0c;让新生们尽快熟悉新的校园和生活&#xff0c;会利用VR全景技术带领着新生进行校园游览&#xff0c;给予新生们巨大便利的同时&a…...

el-checkbox-group限制勾选数量

<!--* Description: 视频监控 页面* Author: mhf* Date: 2023-08-15 13:26:33 --> <template><div class"videoSurveillance"><el-row :gutter"24"><el-col :span"4"><div class"videoSurveillance-left&…...

【JavaScript】WebAPI入门到实战

文章目录 一、WebAPI背景知识1. 什么是WebAPI&#xff1f;2. 什么是API&#xff1f; 二、DOM基本概念三、获取元素三、事件初识1. 点击事件2. 键盘事件 四、操作元素1. 获取/修改元素内容2. 获取/修改元素属性3. 获取/修改表单元素属性4. 获取/修改样式属性 五、操作节点1. 新增…...

奥康的高尔夫鞋,圈不住投资者的心

文 | 螳螂观察 作者 | 青月 鞋服行业终于熬过了“寒冬”&#xff0c;2023年行业景气度开始逐步回暖。 东方财富Choice数据显示&#xff0c;截至8月17日&#xff0c;已有28家鞋帽服装类上市公司发布了2023年中期业绩预告或快报&#xff0c;其中&#xff0c;9家预增&#xff0…...

vue2配置环境变量并且nginx运行成功

需求&#xff1a;我在vue项目配置了生产环境和开发环境&#xff0c;之后通过proxy代理的方式把地址转发到真实的服务器地址上用于请求接口&#xff0c;之后把项目打包后上传到nginx上&#xff0c;之后接口报错404&#xff0c;但是本地运行是可以访问的&#xff0c;找了很久终于…...

Java+Swing形成GUI图像界面

一、Swing 简介 Swing 主要用来开发 GUI 程序,GUI(Graphical User Interface)即图形用户界面。Java 中针对 GUI 设计提供了丰富的类库,这些类分别位于 java.awt 和 java.swing 中,简称 AWT 和 Swing ;其中,AWT(Abstract Window Toolkit)是抽象窗口工具包,是 Java 平…...

编辑距离 -- 动规

72. 编辑距离 给出动规的两种常见实现形式&#xff1a;自顶向下、自底向上&#xff0c;前者一般借助递归函数备忘录实现&#xff0c;后者通常基于dp数组实现。 class MinDistance:"""72. 编辑距离https://leetcode.cn/problems/edit-distance/""&quo…...

douyin【商品抢购js脚本】

文章目录 前言订阅须知知识点源码前言 脚本主要用来实现抢购douyin商城、直播间秒杀商品等一系列商品 订阅须知 订阅后,只提供js源代码,不提供教学,请根据源码自行抓包知识点 1、在查询串插入一个固定的键rstr   2、对查询串进行按键排序并取值,对空格和+进行转义为a …...

常见Web安全技术总结!474页Web安全从入门到精通(附PDF)

Web安全范围比较大&#xff0c;知识点比较杂&#xff0c;很多朋友都无从下手&#xff0c;这不可怕&#xff0c;可怕的是乱下手&#xff0c;其实往往基础才是决定你是否能走远的关键。 为了帮助大家入门网安&#xff0c;给大家推荐一份《新手Web安全入门到精通》&#xff0c;共…...

Prometheus 监控指南:如何可靠地记录数字时间序列数据

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f405;&#x1f43e;猫头虎建议程序员必备技术栈一览表&#x1f4d6;&#xff1a; &#x1f6e0;️ 全栈技术 Full Stack: &#x1f4da…...

rsync远程同步+inotify监控

目录 一、Rsync 简介 1、rsync是什么 2、备份的方式 3、rsync同步方式 4、常用rsync命令 5、配置源的两种表达方法 二、rsync实验 1、本地复制 ​编辑​编辑 2、异地复制 2.1 rsync服务器配置 2.2 rsync客户端配置 2.2.1 普通同步 2.2.2 免密同步 2.2.3 --delet…...

【面试经典150 | 数组】移除元素

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;原地操作 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结构等…...

玩转Mysql系列 - 第21篇:什么是索引?

这是Mysql系列第21篇。 本文开始连续3篇详解mysql索引&#xff1a; 第1篇来说说什么是索引&#xff1f; 第2篇详解Mysql中索引的原理 第3篇结合索引详解关键字explain 本文为索引第一篇&#xff1a;我们来了解一下什么是索引&#xff1f; 路人在搞计算机之前&#xff0c;…...

预处理指令

// The include directive instructs the preprocessor to paste the text of the given file into the current file. // 粘贴指定文件的内容 #include // 定义宏PI #define PI 3.1415926 // 取消定义PI #undef PI条件编译(Conditional Compilation) // 检查xxx是否已被定义为…...

强大的JTAG边界扫描(1):基本原理介绍

文章目录 1. 什么是边界扫描&#xff1f;2. JTAG硬件接口3. 边界扫描相关的软硬件4. 学习资料5. 总结 我是怎么了解到边界扫描的呢&#xff1f; 这就要从我淘到一块FPGA板卡的事情说起了。 前段时间我在某二手平台上淘了一块FPGA板子&#xff0c;它长这样&#xff1a; 板子的…...

【C++】源文件.cpp和头文件.h分离编程

优势介绍 将C代码分为头文件&#xff08;.h&#xff09;和源文件&#xff08;.cpp&#xff09;的做法有以下几个好处&#xff1a; 模块化和代码组织&#xff1a;将函数和类的声明&#xff08;包括函数原型、类的成员和属性等&#xff09;放在头文件中&#xff0c;将函数和类的…...

报错ssh: Could not resolve hostname

…按照网上好多教程试了一下&#xff1a; 新建密钥&#xff0c;添加到gitee&#xff0c;重新测试。修改host&#xff0c;加入gitee的ip地址到里面去。修改.gifconfig配置文件&#xff0c;配置成ssh的仓库链接。 这上面的方法都不行&#xff0c;后面发现一篇文章&#xff1a;SS…...

从零开始学网站建设:从需求分析到上线发布

从零开始学网站建设&#xff1a;从需求分析到上线发布 一、需求分析 在进行网站建设之前&#xff0c;首先需要与客户进行沟通&#xff0c;了解客户的需求和要求&#xff0c;并进行深入的分析和研究。根据不同的需求&#xff0c;需要确定网站的类型、功能、布局、风格等方面的…...

软件系统验收测试需要注意的地方

验收测试 一、软件验收测试含义&#xff1a; 软件验收测试是指测试人员检验软件是否符合软件规格说明书和用户需求的测试活动。 验收测试是软件测试的最后一个环节&#xff0c;也是最为关键的一个要素。 它关系到软件开发公司的产品质量&#xff0c;也关系到需求方的产品能…...

解决three.js中加载纹理贴图时,初次渲染不显示的问题

效果&#xff1a; 解决方法&#xff1a;主要是将一些构建网格对象的操作放在了textureLoader.load()方法中&#xff0c;加载图片也用了require init() {// 1, 创建场景对象this.scene new this.$three.Scene();// 2, 创建立方缓冲几何体this.geometry new this.$three.BoxGe…...

Git学习记录

Contest 一、工作区域二、操作命令2.1 创建仓库2.2 查看仓库状态2.3 从工作区向暂存区添加文件2.3.1 只添加一个文件2.3.2 添加全部文件 2.4 从暂存区向仓库区添加文件2.5 查询日志2.5.1 从当前版本开始查询2.5.2 查看所有日志 2.6 回滚2.6.1 从仓库回滚到工作区2.6.2 取消工作…...

局域网 手机网站建设/百度竞价推广效果怎么样

找到mysql的安装目录的bin/myisamchk工具&#xff0c;在命令行中输入&#xff1a;myisamchk -c -r ../data/tablename/posts.MYI然后myisamchk 工具会帮助你恢复数据表的索引。好象也不用重新启动mysql&#xff0c;问题就解决了。当你试图修复一个被破坏的表的问题时&#xff0…...

做网页收款网站/百度网页版电脑版

详情可参考 : http://www.jianshu.com/p/e28f3c79ba1d 转载于:https://www.cnblogs.com/ianhao/p/4540324.html...

临沂网站公司/电商数据网站

首先&#xff0c;你需要在 Unreal Engine 中创建一个蓝图&#xff0c;然后打开蓝图编辑器。 在蓝图编辑器中&#xff0c;添加一个“事件开始播放”节点。这个节点会在游戏开始时触发。 接下来&#xff0c;添加一个“创建组件”节点&#xff0c;用来创建一个“第三人称摄像机”组…...

在百度上做网站有用吗/衡阳seo服务

一、摘要 本章笔者将详细介绍组织测试代码的相关内容&#xff0c;所用的测试例子会是冒泡排序&#xff0c;笔者在从业这么久之后回想很多面试都要问冒泡排序&#xff0c;虽然不知道为什么要问这个&#xff0c;但还是希望大家掌握&#xff0c;它与自动化测试关系不大属于python的…...

行业网站建设多少钱/韩国搜索引擎排名

# -*- coding: utf-8 -*- """ 姓名区域销售区域 张三湖南100华中 李四湖北50华中 小明河北80华北 小张上海58华东 小宋吉林70东北 小国四川90西北 """ from pyecharts.charts import Bar import xlrd dataxlrd.open_workbook(11.xlsx) tabledata…...

垂直型b2c网站有哪些/网络软营销

文章目录一、引言1.1 数据库压力过大1.2 数据不同步1.3 传统锁失效二、Redis介绍2.1 NoSQL介绍2.2 Redis介绍三、Redis安装3.1 安装Redis3.2 使用redis-cli连接Redis3.3 使用图形化界面连接Redis四、Redis常用命令【重点】4.1 Redis存储数据的结构4.2 string常用命令4.3 hash常…...