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

学习设计模式之观察者模式,但是宝可梦

前言

作者在准备秋招中,学习设计模式,做点小笔记,用宝可梦为场景举例,有错误欢迎指出。

观察者模式

观察者模式定义了一种一对多的依赖关系,一个对象的状态改变,其他所有依赖者都会接收相应的通知。

所以,

  • 何时使用: 一个对象的状态改变,其他所有依赖对象都要知道
  • 意图: 定义一种一对多的依赖关系,一个对象状态改变,所有其他对象都要得到通知
  • 主要解决: 在降低耦合的基础上,实现一对多的协作

观察者模式中,存在四种角色:

  • 主题 (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)甚至会负责维护一个观察者的抽象类的列表,他们之间的联系是紧密的。

第二个区别,发布-订阅模式的消息传递是通过中间代理,而观察者模式是观察者与被观察者之间直接通信。

所以发布-订阅模式是不能跟观察者模式划等号的,观察者模式是一种更为简单的设计理念,而发布-订阅模式适用于更复杂的业务场景。

相关文章:

学习设计模式之观察者模式,但是宝可梦

前言 作者在准备秋招中&#xff0c;学习设计模式&#xff0c;做点小笔记&#xff0c;用宝可梦为场景举例&#xff0c;有错误欢迎指出。 观察者模式 观察者模式定义了一种一对多的依赖关系&#xff0c;一个对象的状态改变&#xff0c;其他所有依赖者都会接收相应的通知。 所…...

课程项目设计--spring security--用户管理功能--宿舍管理系统--springboot后端

写在前面&#xff1a; 还要实习&#xff0c;每次时间好少呀&#xff0c;进度会比较慢一点 本文主要实现是用户管理相关功能。 前文项目建立 文章目录 验证码功能验证码配置验证码生成工具类添加依赖功能测试编写controller接口启动项目 security配置拦截器配置验证码拦截器 …...

学习设计模式之装饰器模式,但是宝可梦

装饰模式 为了不改变组件的结构&#xff0c;动态地扩展其功能。 通常&#xff0c;扩展功能通过子类进行&#xff0c;但是继承的方式具有静态特征&#xff0c;耦合度高。 意图&#xff1a;动态地给对象添加额外的功能 主要解决&#xff1a;继承方式是静态特征&#xff0c;扩…...

【AWS】创建IAM用户;无法登录IAM用户怎么办?错误提示:您的身份验证信息错误,请重试(已解决)

目录 0.背景问题分析 1.解决步骤 0.背景问题分析 windows 11 &#xff0c;64位 我的问题情景&#xff1a; 首先我创建了aws的账户&#xff0c;并且可以用ROOT用户登录&#xff0c;但是在登录时选择IAM用户&#xff0c;输入ROOT的名字和密码&#xff0c;就会提示【您的身份验证…...

微服务基础知识

文章目录 微服务基础知识一、系统架构的演变1、单体应用架构2、垂直应用架构3、分布式SOA架构&#xff08;1&#xff09;什么是SOA&#xff08;2&#xff09;SOA架构 4、微服务架构5、SOA和微服务的关系&#xff08;1&#xff09;SOA&#xff08;2&#xff09;微服务架构 二、分…...

倒残差结构

倒残差结构&#xff1a;   倒残差结构是MobileNetV2中引入的一种设计&#xff0c;用于增强网络的表达能力和特征提取能力&#xff0c;同时保持轻量级的特点。它的核心思想是在每个瓶颈块中&#xff0c;先使用一个扩张卷积&#xff08;Dilated Convolution&#xff09;&#x…...

Docker的基本使用

Docker 概念 Docker架构 docker分为客户端&#xff0c;Docker服务端&#xff0c;仓库 客户端 Docker 是一个客户端-服务器&#xff08;C/S&#xff09;架构程序。Docker 客户端只需要向 Docker 服务端发起请求&#xff0c;服务端将完成所有的工作并返回相应结果。 Docker …...

paddlenlp安装踩坑记录

错误1 ModuleNotFoundError: No module named paddle.metric我下载paddlepaddle-gpu2.5.0.post117解决了&#xff0c;最开始下载的2.5.1报错&#xff0c;post后面的117是我的cuda版本&#xff0c;不要写你对应的版本号 python3 -m pip install paddlepaddle-gpu2.5.0.post117…...

微服务流程引擎:简单又灵活,实现流程全生命周期管理!

伴随着日益激烈的市场竞争&#xff0c;传统的办公操作已经无法满足发展需要了。如果采用微服务流程引擎加油助力&#xff0c;就可以帮助企业更好地管理数据资源&#xff0c;高效做好各种表单制作&#xff0c;实现高效率办公。流辰信息以市场为导向&#xff0c;用心钻研低代码技…...

Qt表格数据处理

概述 在Qt表格数据处理中&#xff0c;涉及到如下几个具体的类&#xff1a; QAbstractItemModel&#xff1a;这是一个抽象基类&#xff0c;定义了模型&#xff08;Model&#xff09;的接口规范。所有的模型类都应该派生自QAbstractItemModel&#xff0c;并实现它的纯虚函数&…...

EasyPOI 实战总结

EasyPOI实战总结 简介 easypoi功能如同名字easy,主打的功能就是容易,让一个没见接触过poi的人员 就可以方便的写出Excel导出,Excel模板导出,Excel导入,Word模板导出,通过简单的注解和模板 语言(熟悉的表达式语法),完成以前复杂的写法 使用EasyPOI 环境搭建 # 1.引入相关依…...

【LeetCode-困难题】42. 接雨水

题目 题解一&#xff1a;暴力双重for循环&#xff08;以行计算水量&#xff09; 1.先找出最高的柱子有多高&#xff08;max 3&#xff09; 2.然后第一个for为行数&#xff08;1&#xff0c;2&#xff0c;3&#xff09; 3.第二个for计算每一行的雨水量&#xff08;关键在于去除…...

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提供了强大的焊件功能&#xff0c;可以帮助工程师们以更高的效率设计焊接件。本文将介绍SOLIDWORKS焊件的概念、特点以及使用方法&#xff0c;以期帮助读者更好地理解和应用这一关键技术。 SOLIDWO…...

2023国赛数学建模D题思路模型代码 高教社杯

本次比赛我们将会全程更新思路模型及代码&#xff0c;大家查看文末名片获取 之前国赛相关的资料和助攻可以查看 2022数学建模国赛C题思路分析_2022国赛c题matlab_UST数模社_的博客-CSDN博客 2022国赛数学建模A题B题C题D题资料思路汇总 高教社杯_2022国赛c题matlab_UST数模社…...

git协议实现管理(三个步骤)

GitHub官网访问&#xff1a; https://github.com/dashboard 初次使用git的用户要使用git协议大概需要三个步骤: 一、生成密钥对 二、设置远程仓库(本文以github为例)上的公钥 三、把git的remote url远程仓库URL可访问路径修改为git协议(以上两个步骤初次设置过以后&#xff0c…...

“深入理解JVM:探索Java虚拟机的内部机制“

标题&#xff1a;深入理解JVM&#xff1a;探索Java虚拟机的内部机制 摘要&#xff1a; Java虚拟机&#xff08;Java Virtual Machine&#xff0c;JVM&#xff09;是Java语言的核心&#xff0c;负责将Java源代码编译成可执行的字节码并运行。本篇博客将深入探索JVM的内部机制&a…...

Unity——各种特效的基本使用方法

特效是游戏制作不可或缺的一环&#xff0c;作为游戏开发者最重要的工作就是将特效添加到游戏中&#xff0c;并在合适的时机、合适的位置将特效播放出来&#xff0c;同时还要注意特效的管理和销毁。 某些种类的特效&#xff0c;如动效、贴花&#xff0c;还要编写脚本代码以实现…...

smiley-http-proxy-servlet 实现springboot 反向代理,结合项目鉴权,安全的引入第三方项目服务

项目中反向代理 集成第三方的服务接口或web监控界面&#xff0c;并实现与自身项目相结合的鉴权方法 依赖 smiley-http-proxy-servlet GitHub链接 2.0 版开始&#xff0c;代理切换到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…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

从物理机到云原生:全面解析计算虚拟化技术的演进与应用

前言&#xff1a;我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM&#xff08;Java Virtual Machine&#xff09;让"一次编写&#xff0c;到处运行"成为可能。这个软件层面的虚拟化让我着迷&#xff0c;但直到后来接触VMware和Doc…...

自然语言处理——文本分类

文本分类 传统机器学习方法文本表示向量空间模型 特征选择文档频率互信息信息增益&#xff08;IG&#xff09; 分类器设计贝叶斯理论&#xff1a;线性判别函数 文本分类性能评估P-R曲线ROC曲线 将文本文档或句子分类为预定义的类或类别&#xff0c; 有单标签多类别文本分类和多…...

恶补电源:1.电桥

一、元器件的选择 搜索并选择电桥&#xff0c;再multisim中选择FWB&#xff0c;就有各种型号的电桥: 电桥是用来干嘛的呢&#xff1f; 它是一个由四个二极管搭成的“桥梁”形状的电路&#xff0c;用来把交流电&#xff08;AC&#xff09;变成直流电&#xff08;DC&#xff09;。…...