学习设计模式之观察者模式,但是宝可梦
前言
作者在准备秋招中,学习设计模式,做点小笔记,用宝可梦为场景举例,有错误欢迎指出。
观察者模式
观察者模式定义了一种一对多的依赖关系,一个对象的状态改变,其他所有依赖者都会接收相应的通知。
所以,
- 何时使用: 一个对象的状态改变,其他所有依赖对象都要知道
- 意图: 定义一种一对多的依赖关系,一个对象状态改变,所有其他对象都要得到通知
- 主要解决: 在降低耦合的基础上,实现一对多的协作
观察者模式中,存在四种角色:
- 主题 (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…...
Linux下C++开发
Linux下C开发 Linux 系统介绍 简介 Linux属于多用户多任务操作系统,而Windows属于单用户多任务操作系统Linux一切皆文件目录结构 bin 存储二进制可执行文件dev 存放的是外接设备,例如磁盘,光盘等。在其中的外接设备是不能直接被使用的&…...
GPT-3.5——从 人工智障 到 大人工智障
有人说,GPT是从人工智障到人工智能的蜕变,但是。。。 我认为,GPT是从 人工智障 到 大人工智障 的退化。。。 从 人工智障 到 大人工智障 GPT-3.5学术介绍No.1---- 西红柿炒钢丝球基本信息详细制作方法材料步骤 幕后花絮 No.2---- 顶尖数学家…...
创建型(四) - 原型模式
一、概念 原型模式(Prototype Pattern):利用对已有对象(原型)进行复制(或者叫拷贝)的方式来创建新对象,以达到节省创建时间的目的。 使用场景:如果对象的创建成本比较大…...
ABAP 定义复杂的数据结构
最近有个需求是实现ABAP数据类型与JASON类型的转换。想要创建个ABAP的数据类型来接JASON类型是个挺麻烦的事。例如下面这个JASON数据,是个很简单的数据结构。但对ABAP来说有4层了,就有点复杂了。 不过ABAP的数据类型也是支持直接定义数据结构的嵌套的。如…...
HCIP第四节-----------------------------BGP
一、BGP基础 1、BGP得概述 (1)、AS OSPF、IS-IS等IGP路由协议在组织机构网络内部广泛应用,随着网络规模扩大,网络中路由数量不断增长,IGP已无法管理大规模网络,AS的概念由此诞生。 AS指的是在同一个组织…...
Temu闯关日韩受挫?跨境电商卖家如何打磨好营销链路
海外版拼多多 Temu 先后在日本和韩国上线,然而效果不似预期,日韩市场对这套“低价补贴”策略并不买账。作为一个尚未被日韩消费者熟悉的网站,其价格之便宜无法让消费者信任。除此之外更大的问题是,在日本卷不过线下零售与百元店&a…...
console的几个常用用法
console.log() 其一、主要表示:向 Web 控制台输出一条消息; 其二、而具体是什么信息就以传递的实参为准,然后就是在控制台就能显示自己传递参数的结果; console.log([1,3,5,7]) // 输出 [1, 3, 5, 7] console.log({}) // 输出 {} conso…...
服务器数据恢复-HP EVA存储VDISK被删除的数据恢复案例
服务器数据恢复环境: 某单位有一台HP EVA存储,连接2组扩展柜,扩展柜中有12块FATA磁盘和10块FC磁盘,不确定数量的LUN,主机安装WINDOWS SERVER操作系统,存储设备用来存放该单位的重要资料。 服务器故障初检&…...
(搜索) 剑指 Offer 13. 机器人的运动范围 ——【Leetcode每日一题】
❓剑指 Offer 13. 机器人的运动范围 难度:中等 地上有一个 m 行 n 列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外)&…...
Java并发编程之线程池详解
目录 🐳今日良言:不悲伤 不彷徨 有风听风 有雨看雨 🐇一、简介 🐇二、相关代码 🐼1.线程池代码 🐼2.自定义实现线程池 🐇三、ThreadPoolExecutor类 🐳今日良言:不悲伤 不彷徨 有风听风 有…...
订阅号怎么做微网站/爱站关键词查询
5月30日,PHPWind精英站长全国巡回沙龙合肥站在合肥市古井假日酒店如期举行。来自全国各地的近400位网站站长和互联网精英齐聚一堂,对站长关心的社区创业、发展、推广、盈利等话题进行了精彩而又深入的探讨。PHPWind运营总监陈燎罕在大会发表了主题演讲&a…...
公司请人做的网站 域名属于谁/站长工具名称查网站
不同类型的消费者1、DefaultMQPushConsumer由系统控制读取操作,收到消息后自动调用传入的处理方法来处理设置好各种参数和传入处理消息的函数。系统收到后自动调用处理函数来处理消息,自动保存Offset,并加入新的消费者之后自动做负载均衡Cons…...
做民族网站的配色哪些颜色适合/如何制作网页
Python 装饰器(Decorator)装饰模式有很多经典的使用场景,例如插入日志、性能测试、事务处理等等,有了装饰器,就可以提取大量函数中与本身功能无关的类似代码,从而达到代码重用的目的。下面就一步步看看Python中的装饰器。装饰器本…...
dedecms 安防监控行业网站模板/凡科建站收费价目表
telnet命令通常用来远程登录。telnet程序是基于TELNET协议的远程登录客户端程序。Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的 能力。在终端使用者的电脑上使用telnet程序&…...
设计公司企业介绍/广州seo网络优化公司
当我们的电脑出现一些问题的时候,很多都可以从bios设置里面进行修改解决问题。这里我们整理了BIOS设置问题详解,如果你遇到问题可以查看相应的进行解决。1.电脑的系统时间不准【故障现象】一台使用了较长时间的兼容机,每次启动后系统的时间都是从1998年1…...
酒店网站报价方案/软文推广名词解释
一、应用背景 还是以宝马汽车制造为例。 随着客户的要求越来越高,宝马车需要不同配置的空调和发动机等配件。于是这个工厂开始生产空调和发动机,用来组装汽车。这时候工厂有两个系列的产品:空调和发动机。宝马320系列配置A型号空调和A型号发动机…...