设计模式篇---观察者模式
文章目录
- 概念
- 结构
- 实例
- 总结
概念
观察者模式:定义对象之间的一种一对多的依赖关系,使得每当一个对象状态发生改变时,其他相关依赖对象都得到通知并被自动更新。
观察者模式是使用频率较高的一个模式,它建立了对象与对象之间的依赖关系,当一个对象发生了改变,自动会通知其他对象。发生改变的对象被称为观察目标,被通知的对象被称为观察者。
当我们看到绿灯就会通过,看到红灯就会停止行走,红灯就是观察目标,我们就是观察者,红灯只有一个,而我们是一群人,也就是说一个目标可以对应多个观察者。
结构
观察者模式的类图如下:

Subject(目标):目标也称为主题,也就是被观察的对象。我们可以在目标中定义一个观察者集合,它提供方法来增加或者删除观察者对象,同时它最主要的方法是通知方法notify,可以通知观察者。
ConcreteSubject(具体目标):它是目标的子类,当它的状态发生改变时,主要是用来向各个观察者发送通知。
Observer(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口。
ConcreteObserver(具体观察者):它是观察者的子类,在具体观察者中维护了一个指向具体目标的引用。
实例
在某多人联机对战游戏中,多个玩家可以加入同一战队组成联盟,当战队中的一人遭到敌人攻击时将给所有的其他盟友发送通知,盟友收到通知后将做出反应。
如果不用设计模式,正常的链路是这样的:联盟成员遭到攻击---->通知给盟友---->盟友做出反应,这样的弊端是如果盟友有很多,则每一个成员都需要进行关联,耦合性太严重。加入观察模式的话,以指挥部作为一个新的对象,链路变成这样:联盟成员遭到攻击---->通知指挥部---->指挥部通知所有盟友---->盟友做出反应。

AllyControlCenter,指挥部中心,充当抽象目标类
@Data
public abstract class AllyControlCenter {protected String allyName;protected ArrayList<Observer> players = new ArrayList<>();public void join (Observer obs){System.out.println(obs.getName()+ "加入"+ this.allyName + "战队");players.add(obs);}public void quit(Observer obs){System.out.println(obs.getName()+ "退出"+ this.allyName + "战队");players.remove(obs);}public abstract void notifyObserver(String name);
}
ConcreteAllyControlCenter类,充当具体目标类
@Data
public class ConcreteAllyControlCenter extends AllyControlCenter {public ConcreteAllyControlCenter(String allyName) {System.out.println(allyName + "战队组建成功");this.allyName = allyName;}@Overridepublic void notifyObserver(String name) {System.out.println(this.allyName + "战队紧急通知,盟友" + name + "遭到敌人攻击");for (Observer player : players) {if (!name.equals(player.getName())) {player.help();}}}
}
Observer,抽象观察者
public interface Observer {String getName();void setName(String name);void help();void beAttacked(AllyControlCenter acc);}
Player,具体观察者
public class Player implements Observer {private String name;public Player(String name) {this.name = name;}@Overridepublic String getName() {return name;}@Overridepublic void setName(String name) {this.name = name;}@Overridepublic void help() {System.out.println("坚持住" + this.name + "来救你");}@Overridepublic void beAttacked(AllyControlCenter acc) {System.out.println(this.name + "被攻击");acc.notifyObserver(name);}
}
客户端
public class Client {public static void main(String[] args) {AllyControlCenter allyControlCenter;allyControlCenter = new ConcreteAllyControlCenter("联盟");Observer play1, play2, play3;play1 = new Player("play1");allyControlCenter.join(play1);play2 = new Player("play2");allyControlCenter.join(play2);play3 = new Player("play3");allyControlCenter.join(play3);play1.beAttacked(allyControlCenter);}}
打印结果:

具体调用流程:Player.beAttacked()—> AllyControlCenter.notifyObserver()—>Player.help()
另外,jdk 的util 包中自带观察者模式,我们可以直接继承和实现这两个类,使用起来更加方便。

总结
观察者模式的优点:
1、表示层和数据逻辑层分离,并抽象了更新的接口,便于不同的表示层充当观察者角色。
2、在观察目标和观察者之间建立了一个抽象的耦合。观察者目标只需要维护一个抽象的观察者集合即可,无需了解具体观察者。
3、简化了一对多系统的难度,支持广播通信。
4、符合开闭原则,增加新的观察者无需修改原代码。
观察者模式的缺点:
1、观察者太多的话,有性能问题。
2、如果观察者和观察目标之间存在循环依赖,可能导致系统崩溃。
3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,仅仅是知道目标发生了变化。
适用环境:
1、当一个抽象模型的一方面依赖另一方面时,可以考虑观察者模式。
2、一个对象的改变导致多个对象发生变动时。
3、需要在系统中新建一个触发链,A对象变动影响B对象,B对象变动影响C对象。
相关文章:
设计模式篇---观察者模式
文章目录 概念结构实例总结 概念 观察者模式:定义对象之间的一种一对多的依赖关系,使得每当一个对象状态发生改变时,其他相关依赖对象都得到通知并被自动更新。 观察者模式是使用频率较高的一个模式,它建立了对象与对象之间的依赖…...
Docker常用命令Top20
Docker常用命令Top20 Docker是一种容器化平台,通过使用Docker,开发人员可以轻松地打包、交付和运行应用程序。以下是Docker中最常用的20个命令: docker run: 运行一个容器。 docker run <image_name>docker ps:…...
Redis的发布订阅机制及其使用场景
Redis的发布订阅(Pub/Sub)机制是一种消息通信模式,其中发送者(发布者)将消息发送到特定的频道,而订阅者则订阅其中一个或多个频道,以接收感兴趣的消息。这种模式可以用于构建实时通信系统、消息…...
计算机网络的基础知识
网络的性能指标:网络速率,bpsbit/s; 时延包括四个组成部分:发送时延、传播时延、排队时延、处理时延; 网络各个层次结构设计的基本三原则:各个层次之间是相互独立的,每一个层之间有足够的灵活…...
QT-Http post 同步请求
在 Qt 中,你可以使用 QNetworkAccessManager 对象的 sendCustomRequest 方法来发送同步的 HTTP 请求。以下是一个演示如何使用该方法发送同步 HTTP POST 请求的示例代码: #include <QCoreApplication> #include <QNetworkAccessManager> #i…...
【JVM】StringTable 字符串常量池
参考:javaGuide 字符串常量池 是 JVM 为了提升性能和减少内存消耗针对字符串(String 类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建 String的不可变性 1.通过字面量的方式(区别于new)给一个…...
Unity中URP实现水体(水的焦散)
文章目录 前言一、原理1、 通过深度图,得到 对应像素 在 世界空间下的Z值2、得到模型顶点在 观察空间 下的坐标3、由以上两点得到 深度图像素 对应的 xyz 值4、最后,转化到 模型本地空间下,用其对焦散纹理采样 二、实现1、获取深度图2、在顶点…...
vue构建版本
完整版:同时包含编译器和运行时的版本。 编译器:用来将模板字符串编译成为 JavaScript 渲染函数的代码。 运行时runtime:用来创建 Vue 实例、渲染并处理虚拟 DOM 等的代码。基本上就是除去编译器的其它一切。 UMD:UMD 版本可以…...
Docker挂载镜像到本地(日常记录)
Docker挂载镜像到本地 1、进入jar包文件夹 cd docker-publish/2、编写DockFile文件 #使用Jdk8环境作为基础镜像,如果镜像不在本地则会从DockerHub进行下载 #FROM openjdk:8-jdk-alpine FROM openjdk:11 #VOLUME 指定了临时文件目录为/tmp。其效果是在主机 /var/l…...
【Elasticsearch查询】精确查询
文章目录 复合查询constant_score querybool querydis_max queryfunction_score queryboosting query单层嵌套双层嵌套 词项查询term query(词项查询)数字的精确查询文本的精确查询查询优化 terms query(多词项查询)terms_set que…...
小狐狸chat2.7.2免授权修复版可用版
小狐狸chat2.7.2免授权修复版可用版 在网络上面找了好几个版本不能使用,今天发布这个仔细测试正常使用 主要功能:独立版无限多开支持分销会员充值自己APP打包小程序万能创作MJ绘图多个国内接口 国外很火的ChatGPT,这是一种基于人工智能技术…...
通过QScrollArea寻找最后一个弹簧并且设置弹簧大小
项目原因,最近需要通过QScrollArea寻找其中最后一个弹簧并且设置大小和策略,因为无法直接调用UI指针,所以只能用代码寻找。 直接上代码: if (m_scrollArea){int iScrollWidth m_labelSelectedTitle->width();m_scrollArea-&g…...
為什麼使用海外動態代理IP進行網路爬蟲?
網路爬蟲作為獲取網路數據的重要工具,其重要性不言而喻。但隨著網站反爬策略的日益嚴格,爬蟲任務變得愈發困難,不過海外動態代理IP可以很好地解決這一問題。本文將詳細闡釋動態代理IP在爬蟲中的應用,以及如何使用動態代理IP提升爬…...
LeetCode 热题100 刷题笔记
一:哈希表 一般哈希表都是用来快速判断一个元素是否出现集合里。 直白来讲其实数组就是一张哈希表,哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素。 1.两数之和 题目链接:. - 力扣(LeetCode…...
veridata安装
GoldenGate Veridata是GoldenGate中用于比较数据库间数据同步效果的一个对比软件。Veridata基于Web,支持大据量的数据对比,能够在不停止数据同步的情况下就可以比较数据。 1、安装veridata前我们都会先安装 middleware infrastructure 这时我们会添加几个…...
面试笔记系列三之spring基础知识点整理及常见面试题
目录 如何实现一个IOC容器? 说说你对Spring 的理解? 你觉得Spring的核心是什么? 说一下使用spring的优势? Spring是如何简化开发的? IOC 运行时序 prepareRefresh() 初始化上下文环境 obtainFreshBeanFactory() 创建并…...
面试笔记系列四之SpringBoot+SpringCloud+计算机网络基础知识点整理及常见面试题
目录 Spring Boot 什么是 Spring Boot? Spring Boot 有哪些优点? SpringBootApplication注解 Spring Boot 的启动流程 Spring Boot属性加载顺序 springboot自动配置原理是什么?(*) 如何理解springboot中的start…...
Kernel[Device Tree] - 1. 设备树的由来
内核代码中,arch文件夹下,是各个架构相关的代码,arm也在里面。 arm子文件夹下,有mach-xxx的目录,就是针对各个芯片类型的,比如mach-imx就是imx系列的芯片。 再里面就是具体的芯片或SOC,比如ma…...
第十四天-网络爬虫基础
目录 1.什么是爬虫 2.网络协议 OSI七层参考模型 TCP/IP模型 1.应用层 2.传输层 3.网络层 3.HTTP协议 1.介绍 2.http版本: 3.请求格式 4.请求方法 5.HTTP响应 状态码: 6.http如何连接 4.Python requests模块 1.安装 2.使用get/post 3.响…...
Linux系统安装
Linux系统安装 安装包链接 链接:https://pan.baidu.com/s/1FdP7TH90UvKUQuiL2yeGCA 提取码:c49n安装包内容 虚拟机执行文件 详细安装教程 虚拟机密钥 Ubuntu 安装步骤 先点击虚拟机的.EXE文件安装,打开安装教程,有详细的说明。...
XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
