学习设计模式之观察者模式,但是宝可梦
前言
作者在准备秋招中,学习设计模式,做点小笔记,用宝可梦为场景举例,有错误欢迎指出。
观察者模式
观察者模式定义了一种一对多的依赖关系,一个对象的状态改变,其他所有依赖者都会接收相应的通知。
所以,
- 何时使用: 一个对象的状态改变,其他所有依赖对象都要知道
- 意图: 定义一种一对多的依赖关系,一个对象状态改变,所有其他对象都要得到通知
- 主要解决: 在降低耦合的基础上,实现一对多的协作
观察者模式中,存在四种角色:
- 主题 (Subject): 被观察者,它要有能通知的状态,要维护一个观察者列表。
- 观望者(Observer): 观察者,接收主题的通知。需要有一个更新方法,接收到主题状态改变后调用。
- 具体主题(Concrete Subject): 主题的实现类。
- 具体观察者(Concrete Observer): 观察者的实现类,实现更新方法。
是不是觉得,四种角色突然被引入,十分抽象?别急,看看下面的故事。
1. 情景模拟
现在宝可梦研究所业务如日中天,人人都想开个研究所狠狠地赚一笔。
但是想要开宝可梦研究所,那肯定得先把宝可梦研究透啊,怎么研究呢?先抓回来!
所以新开的小木博士研究所就打算把关都地区和城都地区的宝可梦都给抓来再说。
小木博士决定,雇点训练家来抓宝可梦,于是大量的训练家都来兼职。
作为亲属的小智和小茂也来兼职帮个忙,小智负责关都地区,小茂负责成都地区。
为了控制成本,每种宝可梦抓一只就够了,所以,每当一个训练家抓到一个精灵,就要通知一下其他同行:
某个地区已经抓住了多少个精灵啦,总共还剩多少个,以免大家抓到重复。
(当然,因为小智和小茂是家属,所以开点小灶,只通知了他俩。)
于是可以引入了观察者模式的各个对象:
- 主题: 研究所的业务
- 观察者: 训练家
- 具体主题: 抓宝可梦的任务
- 具体观察者: 负责不同地区的训练家

2. 代码
先随便定义一个主题的接口
public interface SubjectLab {
}
定义观察者的接口,即训练家,其中,观察者依赖他要观察的Subject类
/*** 训练家*/
public abstract class ObserverTrainer {protected SubjectPokedex subject;public abstract void update();
}
小智和小茂分别负责各自地区
public class Satoshi extends ObserverTrainer{// 该对象观察这个Subject// 同时Subject也绑定这个对象,会发送通知public Satoshi(SubjectPokedex pokedex) {this.subject = pokedex;this.subject.employ(this);}@Overridepublic void update() {System.out.println("I am Satoshi! I got the message:");this.subject.getDexState("Kanto");}
}public class Shigeru extends ObserverTrainer{public Shigeru(SubjectPokedex subject) {this.subject = subject;this.subject.employ(this);}@Overridepublic void update() {System.out.println("I am Shigeru! I got the message:");this.subject.getDexState("Johto");}
}
最后是这次抓宝可梦任务的实现类
public class SubjectPokedex implements SubjectLab{private List<ObserverTrainer> trainers = new ArrayList<>();private HashMap<String, Integer> pokedex = new HashMap<>();private Integer num;/*** 初始化,假设各个地区已经发现了很多宝可梦* 还有value个宝可梦没有被抓到研究所研究* num统计总数*/public SubjectPokedex() {pokedex.put("Kanto", 155);pokedex.put("Johto", 155);num = 310;}/*** 打印某地区剩下的宝可梦* @param region 地区*/public void getDexState(String region){System.out.println("There are still " + pokedex.getOrDefault(region, 0) + " Pokemons in " +region + " that haven't been captured.");System.out.println("There are a total of " + num +" Pokemon that have not been captured yet.\n");}/*** 抓获了num个宝可梦*/public void catchPokemon(String region, Integer num){this.pokedex.put(region, pokedex.get(region) - num);this.num -= num;notifyAllTrainers();}/*** 任命愿意来帮助捕捉宝可梦的训练家们* @param trainer 训练家*/public void employ(ObserverTrainer trainer){trainers.add(trainer);}/*** 通知所有参与的训练家*/public void notifyAllTrainers(){for (ObserverTrainer trainer : trainers) {trainer.update();}}
}
测试类
public class ObserverDemo {public static void main(String[] args) {// Subject对象SubjectPokedex subjectPokedex = new SubjectPokedex();// 两个观察者,接收Subject的通知new Satoshi(subjectPokedex);new Shigeru(subjectPokedex);// 通知:关都地区抓住了30只subjectPokedex.catchPokemon("Kanto", 30);// 通知:城都地区抓住了90只subjectPokedex.catchPokemon("Johto", 90);}
}
I am Satoshi! I got the message:
There are still 125 Pokemons in Kanto that haven't been captured.
There are a total of 280 Pokemon that have not been captured yet.I am Shigeru! I got the message:
There are still 155 Pokemons in Johto that haven't been captured.
There are a total of 280 Pokemon that have not been captured yet.I am Satoshi! I got the message:
There are still 125 Pokemons in Kanto that haven't been captured.
There are a total of 190 Pokemon that have not been captured yet.I am Shigeru! I got the message:
There are still 65 Pokemons in Johto that haven't been captured.
There are a total of 190 Pokemon that have not been captured yet.
3.应用
笔者水平有限,暂时不知道Java哪个常用API用到了观察者模式。
不过可以根据这个思想大概猜测,一种注册端口,再监听的做法和这个差不多。
如果你的微博关注了某人,TA发微博时会推送给你,关注这个行为就相当于是你开始观察这个人(Subject).
或者Steam心愿单添加了某款游戏,这游戏降价时也会推送给你,推送给每个观察者(添加愿望单的玩家).
4.和发布-订阅模式的讨论
有了解过消息队列的聪明的训练家就会感觉:这和发布-订阅模式很像啊!
在查阅资料的过程中,发现有些博主会把发布-订阅模式与观察者模式划等号,其实细品的话还是有一些区别。
我认为最大的区别在于,发布-订阅模式的主要目的是将发布者与订阅者解耦,发布者将消息发送给中间代理,然后代理分发消息给订阅者,让订阅者和发布者之间无需互相关注。
而观察者模式,强调的是观察者和被观察者之间的联系,被观察者(Subject)甚至会负责维护一个观察者的抽象类的列表,他们之间的联系是紧密的。
第二个区别,发布-订阅模式的消息传递是通过中间代理,而观察者模式是观察者与被观察者之间直接通信。
所以发布-订阅模式是不能跟观察者模式划等号的,观察者模式是一种更为简单的设计理念,而发布-订阅模式适用于更复杂的业务场景。
相关文章:
学习设计模式之观察者模式,但是宝可梦
前言 作者在准备秋招中,学习设计模式,做点小笔记,用宝可梦为场景举例,有错误欢迎指出。 观察者模式 观察者模式定义了一种一对多的依赖关系,一个对象的状态改变,其他所有依赖者都会接收相应的通知。 所…...
课程项目设计--spring security--用户管理功能--宿舍管理系统--springboot后端
写在前面: 还要实习,每次时间好少呀,进度会比较慢一点 本文主要实现是用户管理相关功能。 前文项目建立 文章目录 验证码功能验证码配置验证码生成工具类添加依赖功能测试编写controller接口启动项目 security配置拦截器配置验证码拦截器 …...
学习设计模式之装饰器模式,但是宝可梦
装饰模式 为了不改变组件的结构,动态地扩展其功能。 通常,扩展功能通过子类进行,但是继承的方式具有静态特征,耦合度高。 意图:动态地给对象添加额外的功能 主要解决:继承方式是静态特征,扩…...
【AWS】创建IAM用户;无法登录IAM用户怎么办?错误提示:您的身份验证信息错误,请重试(已解决)
目录 0.背景问题分析 1.解决步骤 0.背景问题分析 windows 11 ,64位 我的问题情景: 首先我创建了aws的账户,并且可以用ROOT用户登录,但是在登录时选择IAM用户,输入ROOT的名字和密码,就会提示【您的身份验证…...
微服务基础知识
文章目录 微服务基础知识一、系统架构的演变1、单体应用架构2、垂直应用架构3、分布式SOA架构(1)什么是SOA(2)SOA架构 4、微服务架构5、SOA和微服务的关系(1)SOA(2)微服务架构 二、分…...
倒残差结构
倒残差结构: 倒残差结构是MobileNetV2中引入的一种设计,用于增强网络的表达能力和特征提取能力,同时保持轻量级的特点。它的核心思想是在每个瓶颈块中,先使用一个扩张卷积(Dilated Convolution)&#x…...
Docker的基本使用
Docker 概念 Docker架构 docker分为客户端,Docker服务端,仓库 客户端 Docker 是一个客户端-服务器(C/S)架构程序。Docker 客户端只需要向 Docker 服务端发起请求,服务端将完成所有的工作并返回相应结果。 Docker …...
paddlenlp安装踩坑记录
错误1 ModuleNotFoundError: No module named paddle.metric我下载paddlepaddle-gpu2.5.0.post117解决了,最开始下载的2.5.1报错,post后面的117是我的cuda版本,不要写你对应的版本号 python3 -m pip install paddlepaddle-gpu2.5.0.post117…...
微服务流程引擎:简单又灵活,实现流程全生命周期管理!
伴随着日益激烈的市场竞争,传统的办公操作已经无法满足发展需要了。如果采用微服务流程引擎加油助力,就可以帮助企业更好地管理数据资源,高效做好各种表单制作,实现高效率办公。流辰信息以市场为导向,用心钻研低代码技…...
Qt表格数据处理
概述 在Qt表格数据处理中,涉及到如下几个具体的类: QAbstractItemModel:这是一个抽象基类,定义了模型(Model)的接口规范。所有的模型类都应该派生自QAbstractItemModel,并实现它的纯虚函数&…...
EasyPOI 实战总结
EasyPOI实战总结 简介 easypoi功能如同名字easy,主打的功能就是容易,让一个没见接触过poi的人员 就可以方便的写出Excel导出,Excel模板导出,Excel导入,Word模板导出,通过简单的注解和模板 语言(熟悉的表达式语法),完成以前复杂的写法 使用EasyPOI 环境搭建 # 1.引入相关依…...
【LeetCode-困难题】42. 接雨水
题目 题解一:暴力双重for循环(以行计算水量) 1.先找出最高的柱子有多高(max 3) 2.然后第一个for为行数(1,2,3) 3.第二个for计算每一行的雨水量(关键在于去除…...
npm install 安装依赖,报错 Host key verification failed
设置 git 的身份和邮箱 git config --global user.name "你的名字" > 用户名 git config --global user.email “你的邮箱" > 邮箱进入 > 用户 > [你的用户名] > .ssh文件夹下,删除 known_hosts 文件即可 进入之后有可能会看到 known_hosts…...
SOLIDWORKS焊件是什么?
SOLIDWORKS是一款广泛应用于机械设计领域的三维计算机辅助设计软件。SOLIDWORKS提供了强大的焊件功能,可以帮助工程师们以更高的效率设计焊接件。本文将介绍SOLIDWORKS焊件的概念、特点以及使用方法,以期帮助读者更好地理解和应用这一关键技术。 SOLIDWO…...
2023国赛数学建模D题思路模型代码 高教社杯
本次比赛我们将会全程更新思路模型及代码,大家查看文末名片获取 之前国赛相关的资料和助攻可以查看 2022数学建模国赛C题思路分析_2022国赛c题matlab_UST数模社_的博客-CSDN博客 2022国赛数学建模A题B题C题D题资料思路汇总 高教社杯_2022国赛c题matlab_UST数模社…...
git协议实现管理(三个步骤)
GitHub官网访问: https://github.com/dashboard 初次使用git的用户要使用git协议大概需要三个步骤: 一、生成密钥对 二、设置远程仓库(本文以github为例)上的公钥 三、把git的remote url远程仓库URL可访问路径修改为git协议(以上两个步骤初次设置过以后,…...
“深入理解JVM:探索Java虚拟机的内部机制“
标题:深入理解JVM:探索Java虚拟机的内部机制 摘要: Java虚拟机(Java Virtual Machine,JVM)是Java语言的核心,负责将Java源代码编译成可执行的字节码并运行。本篇博客将深入探索JVM的内部机制&a…...
Unity——各种特效的基本使用方法
特效是游戏制作不可或缺的一环,作为游戏开发者最重要的工作就是将特效添加到游戏中,并在合适的时机、合适的位置将特效播放出来,同时还要注意特效的管理和销毁。 某些种类的特效,如动效、贴花,还要编写脚本代码以实现…...
smiley-http-proxy-servlet 实现springboot 反向代理,结合项目鉴权,安全的引入第三方项目服务
项目中反向代理 集成第三方的服务接口或web监控界面,并实现与自身项目相结合的鉴权方法 依赖 smiley-http-proxy-servlet GitHub链接 2.0 版开始,代理切换到jakarta servlet-api<!--HTTP 代理 Servlet--><dependency><groupId>org.mit…...
(vue)多级表头且转为百分比显示
(vue)多级表头且转为百分比显示 <el-table-column align"center" label"近三个月数据情况"><el-table-column align"center" prop"amount" :label"tableLast[0]"><template slot-scope"{ row }"&g…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
基于IDIG-GAN的小样本电机轴承故障诊断
目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) 梯度归一化(Gradient Normalization) (2) 判别器梯度间隙正则化(Discriminator Gradient Gap Regularization) (3) 自注意力机制(Self-Attention) 3. 完整损失函数 二…...
Golang——7、包与接口详解
包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...
