最新要闻
- 天天最新:dnf游戏闪退怎么解决方法_dnf游戏闪退
- 停车场闸机防骗能力太弱鸡:博主实测一部手机、一张纸均可通行
- 曾模仿东方甄选直播带货 好未来旗下学而思大规模重启线下招生
- 白皮书:购物平台为2022年度消费者投诉最多的行业
- 天天播报:315前海鲜加工厂的狠活被曝光:硼砂泡出黄金鲍 系明令禁止食品添加剂
- 世界焦点!两只售价3899元:华硕ROG推出魔方幻路由器月曜白限定版
- 环球速递!冲击全球的“硅谷银行破产”到底咋回事?会不会引爆危机?
- 视点!国产AYA新掌机Ayaneo 2 IGN9分好评:价格贵 但很好用!
- 【聚看点】央视3·15晚会官宣明晚举办 这次谁会被曝光?
- 世界最资讯丨配置大升级!新款比亚迪唐DM-i/汉EV冰川蓝实车亮相:绝对吸睛
- 上海测试9辆自动驾驶清扫车 可替代25名环卫工人
- 韩国电视台剪掉杨紫琼获奖感言:鼓励女性部分没了
- 腾讯会议重大调整!取消免费300人不限时会议使用
- 世界看热讯:斥资10亿美元!NASA将开发太空拖船:实现国际空间站受控坠落
- 那些曾被315点过名的品牌怎么样了?英菲尼迪道歉并更换变速箱 汉堡王被罚
- 实时焦点:车圈大V杨学良晒魅族20 Pro真机:极简设计 好看又好用!
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
焦点讯息:观察者模式——学习笔记
观察者模式
介绍
观察者模式是极其重要的一个设计模式,在许多框架都使用了,以及实际开发中也会用到。
定义对象之间的一种一对多的依赖关系,使得每当一个对象的状态发生变化时,其相关的依赖对象都可以得到通知并被自动更新。主要用于多个不同的对象对一个对象的某个方法会做出不同的反应!
以不同观察者从同一个天气台中获取数据为例,实践一下简单而普通的观察者模式实现。在(23GoF)书中也有这个例子,这里借鉴了Observable 进行了一些修改。
(资料图片)
其核心在于理解它的定义、使用场景、以及四个重要的方法:
addObserver(Observer o);
addObserver(Observer o);
addObserver(Observer o);
update(Object o);
update 由 观察者实现,其余的由主题实现。
代码示例
1. Subject 主题接口
/** * @Author CNDA * @Date 2023/3/14 8:42 * @ClassName: Subject * @Description: Subject 主题,一旦有改变则推送给所有已经订阅的观察者或者观察者自己拉取数据 * 注意:这个方案只是做学习,并不适用于多线程以及同步的情况。 * @Version 1.0 */public interface Subject { void addObserver(Observer o); // 添加观察者到列表中 void removeObserver(Observer o); // 从列表中输出观察者 void notifyObserver(Object arg); // 将 arg 的数据发送给所有观察者 int size(); // 返回当前主题的所有订阅者个数}
2. Observer 观察者接口/抽象类 这里是接口实现
public interface Observer { /** * 当主题有变化,会通知所有订阅的 Observer * @param arg 主题变化的数据 * 观察者可以主动 ”拉取“ 或者 由主题 ”推送“ */ void update(Object arg);}
3. 实现 Subject 接口类——WeatherData 类
天气主题为例。
public class WeatherData implements Subject { private float temperature; private float humidity; private float light; private float co_2; private boolean isPush = true; // true 为主动推送,false 为订阅者调用对应getxxx() 方法拉取数据。 // 观察者列表 private final List observers; // 无参构造public WeatherData() { this.observers = new ArrayList<>(); } // 提供 getter() 给观察者拉取数据。 public float getTemperature() { return temperature; } public float getHumidity() { return humidity; } public float getLight() { return light; } public float getCo_2() { return co_2; } public void setPush(boolean isPush){ this.isPush = isPush; } @Override public void addObserver(Observer o) { observers.add(o); } @Override public void removeObserver(Observer o) { int i = observers.indexOf(o); if (i >= 0) { observers.remove(o); } } @Override public void notifyObserver(Object arg) { // 通知 observers 的所有观察者 for (Observer observer : observers) { observer.update(arg); } } // 设置内容、更新数据。 public void setManager(float temperature, float humidity, float light, float co_2){ if (isPush){ Map pramMap = new HashMap<>(); pramMap.put("temperature",temperature); pramMap.put("humidity",humidity); pramMap.put("light",light); pramMap.put("co_2",co_2); push(pramMap); }else { this.temperature = temperature; this.humidity = humidity; this.light = light; this.co_2 = co_2; pull(); } } public void pull(){ notifyObserver(null); } public void push(Map map){ notifyObserver(map); } @Override public int size() { return observers.size(); }// 清理 Observers public void clearObservers(){ observers.clear(); }}
通常基础的观察者模式的落地实现,一般会有一个变量控制:booble change。
change 表示标记已经改变的事实。
在 java.util.Observable 中就有一个这个变量,其主要作用是由主题来规定是否更新数据。
可能有些值需要一定的量变才能代表其数据价值。并不是每次变动都要通知所有订阅者更新数据。
而观察者更新数据的方式又分为 主动推送(push) 和 观察者拉取(pull):
如果有一定量的数据,并不是每个观察者都需要主题推送所有数据,可能只需要个别数据,这个时候就可以向外部暴露接口,让观察者拉取所需要的数据。
4. 实现 Observer 接口类 —— DefaultObserver、BaseObserver
4.1 DisplayElement
public interface DisplayElement { void display();}
所有 Observer 都需要实现这个方法,用于显示打印不同观察者的内容。代表观察者的数据内容展示。
4.2 BaseObserver
使用的是推送数据。
public class BaseObserver implements Observer, DisplayElement { private float temperature; private float humidity; private float light; private float co_2; private Subject subject; @Override public void update(Object arg) { // 解析 arg if (arg instanceof HashMap){ Map map = (Map) arg; this.temperature = map.get("temperature"); this.co_2 = map.get("co_2"); this.light = map.get("light"); this.humidity = map.get("humidity"); } display(); } @Override public void display() { System.out.println("BaseObserver Context temperature : " + this.temperature + " humidity : " + this.humidity + " light : " + this.light + " Co_2 : " + this.co_2); } public BaseObserver(Subject subject) { this.subject = subject; } // 取消订阅 public void unsubscribe() { subject.removeObserver(this); } // 设置主题 public void setSubject(Subject subject) { this.subject = subject; }}
4.3 DefaultObserver
使用的是拉取数据
public class DefaultObserver implements Observer, DisplayElement { private float temperature; private float humidity; private Subject subject; public DefaultObserver(Subject subject) { this.subject = subject; } @Override public void update(Object arg) { // 如果 arg 是 null 则主动拉取 if (subject instanceof WeatherData) { WeatherData weatherData = (WeatherData) subject; this.temperature = weatherData.getTemperature(); this.humidity = weatherData.getHumidity(); } display(); } public void unsubscribe() { subject.removeObserver(this); } // 重置 Subject 引用 public void setSubject(Subject subject) { this.subject = subject; } @Override public void display() { System.out.println("DefaultObserver Context temperature : " + this.temperature + " humidity : " + this.humidity); }}
5. 测试效果
@Testpublic void test01(){ // 主题 WeatherData weatherData = new WeatherData(); // 准备两个观察者 DefaultObserver observer = new DefaultObserver(weatherData); BaseObserver baseObserver = new BaseObserver(weatherData); // 将观察者订阅到列表中 weatherData.addObserver(observer); weatherData.addObserver(baseObserver); // 主题更新数据 weatherData.setManager(32.5f,20.6f,155.6f,16.9f); weatherData.setManager(30.2f,26.9f,504.6f,19.9f); weatherData.setManager(28.9f,10.6f,400.1f,30.9f);}
已知主题默认是推送:
只有 BaseObserver
才有数据更新。
设置 weatherData.setPush(false);
改为由观察者拉取数据。
注意:上面将拉取和推送单独分开了。从而导致在推送时,拉取不到新的数据,反之亦然。
5.1 测试观察者取消订阅
// 主题更新数据weatherData.setManager(32.5f,20.6f,155.6f,16.9f);observer.unsubscribe();weatherData.setManager(30.2f,26.9f,504.6f,19.9f);weatherData.setManager(28.9f,10.6f,400.1f,30.9f);
结果符合预期。
5.2 测试主题清空观察者列表
// 主题更新数据weatherData.setManager(32.5f,20.6f,155.6f,16.9f);weatherData.clearObservers();weatherData.setManager(30.2f,26.9f,504.6f,19.9f);weatherData.setManager(28.9f,10.6f,400.1f,30.9f);
JDK 中的 Observable 可观察者
上面的代码是在学习了观察者模式以及 Observable之后进行一些修改的。
JDK 中有观察者模式的实现方案:Observable
和 Observer
。但是在 JDK 9 中被废弃了,因为存在一些问题。其中最主要的是 Observable
是一个类,不易于扩展,以及各种安全问题。而 Observer
又依赖于 Observable
。
所以这些问题就是 Observable
的黑暗面。
在 Swing 中,也有运用到过观察者模式。
总结
简单来说观察者模式是典型的一对多结构。观察者模式可以方便统一的更新订阅者的数据,观察者可以从主题中获取对应的数据,不关心数据如何产生,以及如何传递,只关心如何使用这些数据。而主题只维护好观察者列表,当数据更新时根据业务情况去通知所有订阅的观察者。达到松耦合、可扩展、易维护的目的。
自己对于模式的一个浅层理解和简单代码实现,可以根据自己的想法围绕着该模式的定义进行设计,也可以看其他优秀的博客和优质的代码,学习精华和思想。
关键词:
世界快看:git提交规范
【全球速看料】早起、冥想、阅读、写作、运动
焦点讯息:观察者模式——学习笔记
天天最新:dnf游戏闪退怎么解决方法_dnf游戏闪退
停车场闸机防骗能力太弱鸡:博主实测一部手机、一张纸均可通行
曾模仿东方甄选直播带货 好未来旗下学而思大规模重启线下招生
白皮书:购物平台为2022年度消费者投诉最多的行业
天天播报:315前海鲜加工厂的狠活被曝光:硼砂泡出黄金鲍 系明令禁止食品添加剂
世界焦点!两只售价3899元:华硕ROG推出魔方幻路由器月曜白限定版
卷起来!!!看了这篇文章我才知道MySQL事务&MVCC到底是啥?
蓝牙Mesh简介(一)设备标识:UUID和Mesh地址
开源免费:分享powershell读写k8s的etcd的脚本库
环球速递!冲击全球的“硅谷银行破产”到底咋回事?会不会引爆危机?
视点!国产AYA新掌机Ayaneo 2 IGN9分好评:价格贵 但很好用!
【聚看点】央视3·15晚会官宣明晚举办 这次谁会被曝光?
世界最资讯丨配置大升级!新款比亚迪唐DM-i/汉EV冰川蓝实车亮相:绝对吸睛
上海测试9辆自动驾驶清扫车 可替代25名环卫工人
干货来袭!3天0基础Python实战项目快速学会人工智能必学数学基础全套(含源码)(第3天)概率分析篇:条件概率、全概率与贝叶斯公式
韩国电视台剪掉杨紫琼获奖感言:鼓励女性部分没了
腾讯会议重大调整!取消免费300人不限时会议使用
世界看热讯:斥资10亿美元!NASA将开发太空拖船:实现国际空间站受控坠落
那些曾被315点过名的品牌怎么样了?英菲尼迪道歉并更换变速箱 汉堡王被罚
实时焦点:车圈大V杨学良晒魅族20 Pro真机:极简设计 好看又好用!
与微软聊天机器人对话
Vue项目迁移小程序,实操干货分享
戴尔PC要100%离开中国!完整时间表曝光:真着急
天天微资讯!韩媒称特斯拉停止与比亚迪合作 马斯克:虚假报道、双方关系积极
魔兽世界将推出全新硬核玩法:一命通关、挂了就得重来
ai文件怎么打开?ai文件用什么软件打开和编辑?
斐讯k1支持千兆吗?斐讯k1路由器怎么设置?
windows如何一键还原?windows截图保存在哪里?
声卡怎么调试?声卡什么牌子的音质比较好?
笔记本fn键在哪里?fn键怎么开启和关闭?
每日短讯:可插拔组件设计机制—SPI
今日热讯:Vim 备忘清单_开发速查表分享
世界头条:Linux进程的创建与销毁
鲨鱼求偶被误认吃“同事” 官方回应:是繁殖行为 撕咬有分寸
天天热文:减肥不吃主食?医生提醒:可致大脑功能衰退
全球热消息:《小丑2》Lady Gaga小丑女新片场照 造型太好看了
全球报道:极速直追中国高铁!碳陶瓷刹车套件特斯拉Model S Plaid打破单圈纪录
【全球报资讯】一键开盖:哈尔斯600ml水杯9.9元狂促 Tritan材质款23.9元
天天热头条丨阳高县气象台发布大风蓝色预警【Ⅳ级/一般】
全球微头条丨java操作excel文件——POI
天天讯息:剑指 Offer 68 - II. 二叉树的最近公共祖先(java解题)
分布式架构-可观测性
obs studio 插件
看热讯:小米子公司发通告:拼多多、京东、淘宝上的“紫米官旗”不是我
硅谷银行停业没影响!贾跃亭要“翻身”:4月26日FF91终极发布
世界今日讯!德国反对2035禁售燃油车!欧盟做出让步:内燃机还有活路
天天观热点:Intel要求电源厂商使用单一规格制作12VHPWR接头
马斯克减肥神药遭疯抢!欧洲药管局警告:2023年都会短缺
天天热讯:DockQuery | 基于E-R图的数据建模功能使用实践
宝马iX3高速撞车 车主:车道纠偏系统和自己抢方向盘酿事故
环球最新:公司回应因给客户倒水太满开除员工:该走啥程序走啥程序
新机型“无可奉告”:任天堂称对Switch未来充满信心
【全球速看料】史上最大规模!魅族领克无界生态发布会官宣:魅族20系列、Flyme 10来了
全球视点!一加逆袭!成为2023年销量增速最快的品牌:友商普遍下滑
共314套房源!昌平区公租房配租公告来了
焦点资讯:GO语言学习笔记-测试篇 Study for Go ! Chapter ten- Test
要闻速递:面试官:怎么删除 HashMap 中的重复元素?第 3 种实现思路,99% 的人不会!
世界快消息!k8s的Helm 工具安装
RPC框架JMH测试-chatgpt自动生成
前端设计模式——代理模式
全球视讯!特斯拉叫停与比亚迪合作?比亚迪回应:不实信息
环球即时:苹果人事巨震:11位高管扎堆离职 库克也要降薪40%
微头条丨燃油车 真凉透了吗
【天天时快讯】采用全新NT架构:新Windows端QQ首个版本将于24日发布
世界资讯:剧版打破多项纪录!爱奇艺考虑拍《狂飙》电影版 网友评论两级分化
每日看点!插件化开发详解
关注:读Java性能权威指南(第2版)笔记16_垃圾回收C
全球滚动:京东小程序CI工具实践
巧妙使用SQL Server的计算列实现项目唯一规则快速定制
天天快资讯:免费玩没戏 《暗黑4》不会加入微软XGP:四五百块还是要花的
首位华裔奥斯卡影后!杨紫琼84岁母亲喜极而泣 为女儿感到自豪
世界微资讯!Redis内存碎片深入分析
多举措提高职教吸引力 助力职业教育“强起来”“活起来”
焦点简讯:曝苹果最快2024年商用MicroLED屏:比OLED更香
今日快讯:7月1日普及!我国将全面淘汰传统后视镜 都换汽车电子后视镜:上游供应链已准备好
全球今日报丨老人捡钱不愿归还 女孩崩溃下跪引网友愤怒:律师称可起诉 专家喊话不能仗着年龄大
环球新动态:适合买二手的硬件只有4个:学会省1000元
K8S-Helm
资讯:04-数据类型
环球动态:在Linux中安装containerd作为kubernetes的容器运行时
当前通讯!“自杀式”降价杀红眼:燃油车真凉透了?
乘客出地铁黄鹤楼站的统一姿势:集体反站拍摄绝美夜景
天天动态:大爷充29万做美容反悔起诉退钱:宣称能打通“任督二脉”等
世界聚焦:硅谷银行破产:在营销号那儿 咋又成美国赢了?
从大厂离职后 游戏程序员们过得咋样?
鲍美瑶男朋友大白_鲍美瑶
即时看!第129篇:JS模块化开发
每日快播:Yus框架之nl子级管控指令
鼻炎患者要注意了!今年花粉高峰期来得猛又早:将持续数月
中消协等倡议推广小份菜、半份菜:鼓励线上点餐推出“菜量自动提醒”功能
焦点速读:《流浪地球2》上映51天票房破40亿 豆瓣评分又涨了!导演自曝第三部
AMD技术岗最高头衔!DX10/11发明人、皓龙处理器之父等升任企业院士
22-23(2)第2次线上赛
【打怪升级】【rocketMq】rocket的持久化
Linux进程与线程的基本概念及区别
天天消息!k8s单节点改为高可用和更新证书
世界滚动:这还是中国乒乓球吗?王牌选手接连倒下,对手赢球后开心改签机票