3分钟看懂设计模式02:观察者模式

一、什么是观察者模式

观察者模式又叫做发布-订阅模式或者源-监视器模式

结合它的各种别名大概就可以明白这种模式是做什么的。

其实就是观察与被观察,一个对象(被观察者)的状态改变会被通知到观察者,并根据通知产生各自的不同的行为。

以下为《设计模式的艺术》中给出的定义:

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

二、观察者模式的4个角色

Subject(目标)

Subject是被观察的对象。

Subject可以是接口、抽象类或者具体类。

它一般有4个要素

• 一个观察者集合,一般用Vector。

• 增加观察者的方法。

• 删除观察者的方法。

• 通知方法notify()。

ConcreteSubject(具体目标)

是Subject的子类,没什么特殊的,如果有抽象方法需要实现就实现,没有的话这个类不写也行。

Observer(观察者)

一般是个接口,声明一个update()方法。

ConcreteObserver(具体观察者)

刚开始学的话先会最简单的形式就可以了,就直接实现Observer接口,实现update()方法就完了。

三、观察者模式2个代码实现案例

通过2个案例,基本就可以知道观察者模式是怎么回事了,对照观察者模式的4个角色,敲一遍。

单纯熟悉4个角色的案例

先写一个被观察者Subject

public abstract class Subject {// 存放观察者的集合private Vector<Observer> obs = new Vector<>();public void addObserver(Observer obs) {this.obs.add(obs);}public void delObserver(Observer obs) {this.obs.remove(obs);}// 通知方法,写成抽象方法让ConcreteSubject实现也一样的protected void notifyObserver() {for (Observer ob : obs) {ob.update();}}// 这里也是可写可不写,根据业务需求public abstract void doSomething();}

再写一个ConcreteSubject

public class ConcreteSubject extends Subject {@Overridepublic void doSomething() {System.out.println("被观察者事件发生改变");this.notifyObserver();}
}

观察者接口Observer

public interface Observer {public void update();
}

观察者实现类ConcreteObserver,我们这里给出2个观察者

public class ConcreteObserver01 implements Observer {@Overridepublic void update() {System.out.println("观察者01收到状态变化信息,并进行处理...");}
}
public class ConcreteObserver02 implements Observer {@Overridepublic void update() {System.out.println("观察者02收到状态变化信息,并进行处理...");}
}

最后给出一个测试类,测试运行一个看看效果,看不明白代码就debug一下捋一捋。

以下代码的意思就是:

你得有东西被观察被监视吧?

所以先创建一个被观察者,比如我的账户余额。

你得设置哪些对象在观察、监视我的账户吧?

那就添加2个,我和我老婆。

然后就坐等账户余额有变化。

一旦发工资,状态变化!!!

图片

dosomething()!

notifyObserver()!

遍历观察者列表!

update()!

这个时候我和我老婆分别对应各自实现的update()方法。

我马上去买了游戏。

我老婆马上去买了化妆品。

(不过这个例子好像不太合适,因为update方法里又会导致账户余额的变化,循环起来了,不过大概明白咋回事就行了。)

    public class Client {public static void main(String[] args) {ConcreteSubject subject = new ConcreteSubject();subject.addObserver(new ConcreteObserver01());subject.addObserver(new ConcreteObserver02());subject.doSomething();}}

盟友受攻击发通知,其他盟友做出响应

这个例子也是《设计模式的艺术》给出的案例。

我们的需求如下:

联盟成员收到攻击→发送通知给盟友→盟友做出响应。

如果按照上述思路设计,则每个成员必须持有其他所有成员的状态信息,导致系统开销过大。所以我们引入一个战队控制中心来统一维护所有战队成员信息。

图片

依然是我们四步走:

先创建一个Subject被观察者,这里是AllyControlCenter控制中心

    public abstract class AllyControlCenter {/*** 战队名称*/protected String allyName;/*** 定义一个集合,用来存储具体观察者,也就是战队成员*/protected Vector<Observer> players = new Vector<Observer>();/*** 加入战队*/public void join(Observer observer) {System.out.println(observer.getName() + "加入" + this.allyName + "战队!");players.add(observer);}/*** 退出战队*/public void quit(Observer observer) {System.out.println(observer.getName() + "退出" + this.allyName + "战队!");players.remove(observer);}/*** 声明抽象通知方法* @param name*/public abstract void notifyObserver(String name);/*** 设置成员变量方法* @param allyName*/public void setAllyName(String allyName) {this.allyName = allyName;}/*** 获取成员变量方法* @return*/public String getAllyName() {return this.allyName;}}

再创建一个ConcreteSubject具体被观察者ConcreteAllyControlCenter

    public class ConcreteAllayControlCenter extends AllyControlCenter {public ConcreteAllayControlCenter(String name) {System.out.println(name + "战队组建成功!");System.out.println("-------------");this.allyName = name;}/*** 实现通知方法* @param name*/@Overridepublic void notifyObserver(String name) {System.out.println(this.allyName + "战队紧急通知,盟友" + name + "遭受敌人攻击");// 遍历观察者集合,调用每一个盟友(除了自己)的支援方法for (Observer obs : players) {if (!obs.getName().equalsIgnoreCase(name)) {obs.help();}}}}

创建一个抽象观察者Observer

    public interface Observer {public String getName();public void setName(String name);/*** 声明支援盟友的方法*/public void help();/*** 声明遭受攻击的方法*/public void beAttacked(AllyControlCenter acc);}

在创建具体观察者Player

public class Player implements Observer {private String name;public Player(String name) {this.name = name;}@Overridepublic String getName() {return this.name;}@Overridepublic void setName(String name) {this.name = name;}/*** 支援盟友的方法实现*/@Overridepublic void help() {System.out.println("坚持住,"+this.name +"来救你了!");}/*** 遭受攻击的方法实现* 当遭受攻击时,调用战队控制中心类的通知方法notifyObserver()来通知盟友* @param acc*/@Overridepublic void beAttacked(AllyControlCenter acc) {System.out.println(this.name + "被攻击!");acc.notifyObserver(name);}
}

测试运行

public class Client {public static void main(String[] args) {// 定义被观察者AllyControlCenter acc = new ConcreteAllayControlCenter("金庸群侠");// 定义4个观察者Observer player1 = new Player("杨过");Observer player2 = new Player("令狐冲");Observer player3 = new Player("张无忌");Observer player4 = new Player("段誉");acc.join(player1);acc.join(player2);acc.join(player3);acc.join(player4);// 某成员遭受攻击player1.beAttacked(acc);}
}

四、我什么时候用观察者模式?

  1. 1. 事件处理系统:例如,用户界面框架中,当用户进行某些操作(如点击按钮、移动鼠标等)时,可以使用观察者模式来通知相关的处理程序。

  2. 2. 数据订阅与发布系统:在需要向多个客户端发布数据更新的场景中,例如股票行情显示、新闻更新等,可以使用观察者模式。

  3. 3. 跨系统的消息交换:例如,在微服务架构中,服务间的事件可以通过观察者模式进行通信,确保各服务间的解耦。

  4. 4. 状态监控和警报系统:在需要监控某些状态并在特定条件下发送警报的系统中,观察者模式可以用来实现监控对象和警报系统之间的通信。

  5. 5. 配置管理:当系统配置信息发生变更时,使用观察者模式可以实时通知各个使用配置的组件进行相应的调整。


往期推荐:

● 师爷,翻译翻译什么叫AOP

● 翻译,师爷师爷什么叫事务

● 纪念JDBC

● SpringBoot实现动态数据源配置‍

● 聚簇索引、回表与覆盖索引

● Java锁到底是个什么东西

图片

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

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

相关文章

VTK通过线段裁剪

线段拆分网格 void retrustMesh(vtkSmartPointer<vtkPolyData> polydata, vtkSmartPointer<vtkPoints> intermediatePoint) {vtkSmartPointer<vtkPoints> srcPoints polydata->GetPoints();int pointSize intermediatePoint->GetNumberOfPoints();/…

【动态规划】【状态压缩】LCP04 覆盖

作者推荐 【广度优先搜索】【网格】【割点】【 推荐】1263. 推箱子 本文涉及知识点 动态规划汇总 LCP04 覆盖 你有一块棋盘&#xff0c;棋盘上有一些格子已经坏掉了。你还有无穷块大小为1 * 2的多米诺骨牌&#xff0c;你想把这些骨牌不重叠地覆盖在完好的格子上&#xff0…

maven3旧版本的下载地址(含新版本)

因为现有的3.8版本与IDEA不兼容&#xff0c;我需要下载3.6版本&#xff0c;但是官网的位置非常隐蔽&#xff0c;找了很多资料才看到。故记录一下。 第一步 进入网址&#xff0c;选择需要的版本 Index of /dist/maven/maven-3 第二步 选择binaries 第三步 选择zip文件下载就可…

【Java程序设计】【C00285】基于Springboot的游戏分享网站(有论文)

基于Springboot的游戏分享网站&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的游戏分享网站 本系统分为系统功能模块、管理员功能模块以及用户功能模块。 系统功能模块&#xff1a;在网站首页可以查看首页、游戏…

uniapp-提现功能(demo)

页面布局 提现页面 有一个输入框 一个提现按钮 一段提现全部的文字 首先用v-model 和data内的数据双向绑定 输入框逻辑分析 输入框的逻辑 为了符合日常输出 所以要对输入框加一些条件限制 因为是提现 所以对输入的字符做筛选,只允许出现小数点和数字 这里用正则实现的 小数点…

IDEA生成Java Doc帮助文档

使用场景 使用IDEA&#xff08;本次使用2020.3版&#xff09;将自己写的常用的工具类打成jar包&#xff0c;安装到maven本地仓库&#xff0c;最后生成对应的doc参考文档。 操作流程 方法一 选中项目 右键 show in Explor&#xff0c;如下图&#xff1a; 选中地址栏 cmd 输入…

无公网IP情况下如何远程查看本地群晖NAS存储的文件资源

文章目录 前言本教程解决的问题是&#xff1a;按照本教程方法操作后&#xff0c;达到的效果是前排提醒&#xff1a; 1. 搭建群晖虚拟机1.1 下载黑群晖文件vmvare虚拟机安装包1.2 安装VMware虚拟机&#xff1a;1.3 解压黑群晖虚拟机文件1.4 虚拟机初始化1.5 没有搜索到黑群晖的解…

Java的编程之旅27——继承

1.继承的简介 继承是面向对象编程中的一个重要概念&#xff0c;指的是一个类可以继承另一个类的属性和方法。被继承的类称为父类或基类&#xff0c;继承这个父类的类称为子类或派生类。 通过继承&#xff0c;子类可以继承父类的属性和方法&#xff0c;使得子类具有相似的行为…

掌握BeautifulSoup4:爬虫解析器的基础与实战【第91篇—BeautifulSoup4】

掌握BeautifulSoup4&#xff1a;爬虫解析器的基础与实战 网络上的信息浩如烟海&#xff0c;而爬虫技术正是帮助我们从中获取有用信息的重要工具。在爬虫过程中&#xff0c;解析HTML页面是一个关键步骤&#xff0c;而BeautifulSoup4正是一款功能强大的解析器&#xff0c;能够轻…

2024年度中国5G随身WiFi品牌排行榜

【中国品牌网中国3C质量评测中心权威榜单联合发布】 第一名&#xff1a;格行 优势&#xff1a;作为随身WiFi行业的佼佼者&#xff0c;格行凭借其15年的物联网行业经验&#xff0c;在技术研发、产品创新及客户服务上均享有盛誉。其5G随身WiFi产品网络稳定&#xff0c;客户满意度…

行为树入门:ROS2 BehaviorTree.CPP Groot2安装与简单使用(有例程)

ROS2安装与学习及其topic学习 BehaviorTree.CPP编译与安装 和 Groot2安装 注意&#xff1a;《ROS2行为树&#xff08;C行为树&#xff09;BehaviorTree.CPP完全图形化开发&#xff0c;完美支持ROS2话题通信》这个例程实现的前提需要建一个sentry_interfaces::msg::RobotHP的m…

Spring Boot 笔记 029 用户模块

1.1 用户信息需要在多个链接使用&#xff0c;所以需要用pinia持久化 1.1.1 定义store import {defineStore} from pinia import {ref} from vue const useUserInfoStore defineStore(userInfo,()>{//定义状态相关的内容const info ref({})const setInfo (newInfo)>{i…

“IT行业职业发展的黄金之路:哪些证书能为你增光添彩?“

文章目录 每日一句正能量前言1、浙大计算机程序设计能力考试证书&#xff08;PAT&#xff09;2、全国计算机等级考试证书(NCRE)3、计算机技术与软件专业资格考试证书&#xff08;软考&#xff09;4、通信专业技术人员职业水平证书5、全国计算机应用水平考试证书&#xff08;NIT…

MySQL学习Day19——索引的数据结构

一、为什么使用索引: 索引是存储引擎用于快速找到数据记录的一种数据结构&#xff0c;就好比一本教课书的目录部分&#xff0c;通过目录中找到对应文章的页码&#xff0c;便可快速定位到需要的文章。MySQL中也是一样的道理&#xff0c;进行数据査找时&#xff0c;首先查看查询…

【深蓝学院】移动机器人运动规划--第6章 模型预测控制(MPC)与运动规划--笔记

0. Outline 1. Reactive Control&#xff08;反应式控制&#xff09; 控制学中的 “Reactive Control” 通常指的是一种控制策略&#xff0c;它依赖于系统对特定事件或变化的即时反应&#xff0c;而不是按照预定的计划或策略行动。这种控制往往是基于当前的传感器输入来做出决…

Mac 上游玩QQ飞车详细教程,IPA砸壳包资源下载安装

最近经过一番折腾终于在 MAC 上成功安装运行了 QQ 飞车&#xff0c;上图&#xff1a; 最后总结下来安装过程其实蛮简单的&#xff0c;但其中有很多卡点和坑所以浪费了很多的时间&#xff0c;特意整理本篇教程供大家参考 大体思路是这样的&#xff0c;先安装 playCover,该软件可…

PostMan使用自带js库base64编码、sha256摘要、环境变量的使用

目录 1、环境变量的使用2、base64编码、sha256摘要、以及脚本的使用3、脚本代码 在请求调试接口的过程中&#xff0c;因为要使用大量相同的参数&#xff0c;使用变量的方式能很大程度上减轻接口调用的工作量 版本说明&#xff1a;Postman for Windows&#xff0c;Version&#…

【Python笔记-设计模式】桥接模式

一、说明 桥接模式是一种结构型设计模式&#xff0c; 主要用于将抽象部分与它的实现部分分离&#xff0c; 从而能在开发时分别使用&#xff0c;使系统更加灵活&#xff0c;易于扩展。 (一) 解决问题 所有 组合类的数量将以几何级数增长 抽象和实现分离&#xff1a;桥接模式可…

数据结构day4

实现创建单向循环链表、创建结点、判空、输出、头插、按位置插入、尾删、按位置删除 loop_list.c #include "loop_list.h" loop_p create_head() {loop_p L(loop_p)malloc(sizeof(loop_list));if(LNULL){printf("空间申请失败\n");return NULL;}L->le…

websocket了解下

websocket请求长啥样 GET /chat HTTP/1.1 Host: example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ Sec-WebSocket-Version: 13 啥是websocket websocket是http的一种&#xff0c;服务器可以主动向客户端推送信息&#xff0c;…