(二)详解观察者模式

一.使用场景

当我们需要一个类,在他的内部元素发生变化的时候可以主动通知其他类的时候,同时要保持良好的可拓展性,可以采用观察者模式。

二.核心

观察者模式=出版者+订阅者

我们拥有一个主题对象,和一些其他对象,包括注册成观察者的类和没有注册成观察者的类。当主题对象内部的元素发生改变,主题对象会通知所有注册成观测者的类。同时任何类可以随时注册成观测者或注销自己的观测者身份。

观测模式定义对象之间的一对多依赖,这样一来当一个对象改变时他的所有依赖着都会受到通知并自动更新。

观测者模式应该做到松耦合,主题唯一知道的事情是,观察者提供了观察者接口。我们可以随时添加新的观测者。同时在添加新的观测者的时候不需要修改主题,可以彼此独立的复用主题或观察者。改变主题或观察者其中一方不会影响另一方

三.例子

假设我们需要一款检测气象的类,在观察到气象数据发生变化后,主动向用户展示当前气象状态。

首先我们需要一个观测者类,任何对象都只要继承了观测者类并实现了更新方法都可以当作当作者来实现。

namespace weather {class Observer {public:virtual ~Observer() = default;virtual void update(float temp, float humidity, float pressure) = 0;    //提供一个虚接口让想成为观测者的对象自己实现更新行为};
}

我们还需要一个主题接口,用来给所有观测者提供更新的业务逻辑。这个主题需要具有接受新注册观测者和溢出观测者的能力,还有具有通知所有观测者信息发生改变的能力。

namespace weather {class Observer; // 前置声明class Subject {public:virtual ~Subject() = default;virtual void registerObserver(Observer* o) = 0;    //接受新注册的观测者virtual void removeObserver(Observer* o) = 0;       //注销当前任意观测者virtual void notifyObservers() = 0;        //通知所有观测者信息已发生改变};
}

为了方便观察我们还可以给所欲需要显示元素创建一个接口,当需要显示的时候,实现这个接口,并直接调用他即可

namespace weather {class DisplayElement {public:virtual ~DisplayElement() = default;virtual void display() const = 0;    //给需要实现显示的类提供接口};
}

 实现完了所有所需接口,我们可以针对应用逻辑设计当前所需要的类了。这对目前要求我们需要一个能主动通知观察者的气象类,我们可以让他作为一个主题类。并管理所有当前观测者,在天气发生变化的时候,调用所有观测者的更新函数进行更新。

namespace weather {class WeatherData : public Subject {public:WeatherData() = default;virtual ~WeatherData() = default;void registerObserver(Observer* o)     //注册观测者{observers.push_back(o);}virtual void removeObserver(Observer* o) //删除观测者{for(auto beg = observers.begin(); beg < observers.end(); beg++){if(*beg == o){beg = observers.erase(beg);}}}virtual void notifyObservers()   //通知所有观测者信息发生改变{for (auto observer : observers) //遍历所有的观测者{observer->update(temperature, humidity, pressure);    //调用所有观测者自己提供的更新函数}}void measurementsChanged()    //当气象信息发生改变时,会调用这个函数。给下一层提供,由下 一层调用。{notifyObservers();        //通知所有观测者} void setMeasurements(float temperature, float humidity, float pressure);    //设置天气值,便于调试{temperature = temp;humidity = h;pressure = p;measurementsChanged();}private:std::vector<Observer*> observers;   //管理所有观测者float temperature;  //当前天气的的信息float humidity;float pressure;};
}

接下来我们可以创建一个观测者对象用于在天气温度变化时打印出来当前值。观测者对象可以无限拓展。

namespace weather {class StatisticsDisplay : public Observer, public DisplayElement {private:float maxTemp = 0.0f;float minTemp = 200;float tempSum= 0.0f;int numReadings;Subject& weatherData;public:explicit StatisticsDisplay(Subject& inWeatherData)    //通过构造函数把它注册为观察者: maxTemp(0.0f), minTemp(200), tempSum(0.0f), numReadings(0), weatherData(weatherData){weatherData.registerObserver(this);    }~StatisticsDisplay(){weatherData.removeObserver(this);    //将当前类从观察者中移除}void update(float temperature, float humidity, float pressure)    //获取到更新后的值后和当前值进行对比{tempSum += temp;numReadings++;if (temp > maxTemp) {maxTemp = temp;}if (temp < minTemp) {minTemp = temp;}display();    //打印显示}void display() const //提供自己的打印方法{std::cout << "Avg/Max/Min temperature = " << (tempSum / numReadings)<< "/" << maxTemp << "/" << minTemp << std::endl;}};
}

我们可以根据这样的模板根据需求提供不同的的观察者。

四.优化

按照上面的逻辑去写,每次发生任意一个元素的改变,都会推送给所有的观测者。不论这个观测者需不需要这些数据。我们可以让观测者根据需求从主题类里拉取需要的元素。我们可以在主题类调用观察者类的update函数的时候不传任何参数。然后我们修改主题类,在内部提供get函数用于获取自己的参数。最后我们在update函数被调用的时候通过调用get函数,去向主题类索取自己需要的元素。

总而言之,就是指让观测者知道值已经发生改变。让观测者自己去要具体哪个值。

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

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

相关文章

Spring Cloud Zuul 基本原理

Spring Cloud Zuul 底层是基于Servlet实现的&#xff0c;核心是通过一系列的ZuulFilter来完成请求的转发。 1、核心组件注册 1.1. EnableZuulProxy注解 启用Zuul作为微服务网关&#xff0c;需要在Application应用类加上EnableZuulProxy注解&#xff0c;而该注解核心是利用Im…

PS端GPIO配置和基本介绍

Xilinx PS GPIO 驱动程序。 该驱动程序支持 Xilinx PS GPIO 控制器。 GPIO 控制器支持以下功能&#xff1a; The GPIO Controller supports the following features: 4 banksMasked writes (There are no masked reads)屏蔽写入Bypass mode 旁路模式Configurable Interrupts…

RandomForestClassifier 与 GradientBoostingClassifier 的区别

RandomForestClassifier&#xff08;随机森林分类器&#xff09;和GradientBoostingClassifier&#xff08;梯度提升分类器&#xff09;是两种常用的集成学习方法&#xff0c;它们之间的区别分以下几点。 1、基础算法 RandomForestClassifier&#xff1a;随机森林分类器是基于…

@SpringBootApplication注解的理解——如何排除自动装配 分布式情况下如何自动加载 nacos是怎么被发现的

前言 spring作为主流的 Java Web 开发的开源框架&#xff0c;是Java 世界最为成功的框架&#xff0c;持续不断深入认识spring框架是Java程序员不变的追求。 本篇博客介绍SpringBootApplicant注解的自动加载相关内容 其他相关的Spring博客文章列表如下&#xff1a; Spring基…

2023 年热门的大型语言模型 (LLMs)汇总【更新至9月26】

一、全景地图 整理了一张大语言模型的血缘图谱&#xff0c;如下图所示&#xff1a; 图中的大语言模型&#xff0c;都是自己做过评测的&#xff0c;主观了点&#xff0c;但是原汁原味&#xff0c;有好的可以推荐给我。 二、ChatGPT系列 ChaTGP是商业版本大语言模型的正统&…

逆强化学习

1.逆强化学习的理论框架 1.teacher的行为被定义成best 2.学习的网络有两个&#xff0c;actor和reward 3.每次迭代中通过比较actor与teacher的行为来更新reward function&#xff0c;基于新的reward function来更新actor使得actor获得的reward最大。 loss的设计相当于一个排序问…

visual studio禁用qt-vsaddin插件更新

visual studio里qt-vsaddin插件默认是自动更新的&#xff0c;由于qt-vsaddin插件新版本的操作方式与老版本相差较大&#xff0c;且新版本不稳定&#xff0c;容易出Bug&#xff0c;所以需要禁用其自动更新&#xff0c;步骤如下&#xff1a;     点击VS2019菜单栏上的【扩展】–…

【Ansible自动化运维实战】使用Ansible部署WordPress应用

【Ansible自动化运维实战】使用Ansible部署WordPress应用 一、Ansible介绍1.1 Ansible简介1.2 Ansible特点二、wordpress介绍2.1 wordpress简介2.2 wordpress特点三、本次实践规划3.1 本次实践介绍3.2 本次实践规划四、部署ansible环境4.1 配置yum仓库4.2 安装ansible4.3 配置a…

基于Java的毕业设计选题管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

实现springboot的简单使用~

在之前学习SpringSpringMVCMybatis框架时&#xff0c;我们学习了多种配置spring程序的方式&#xff0c;例如&#xff1a;使用XML&#xff0c;注解&#xff0c;Java配置类&#xff0c;或者是将它们结合使用&#xff0c;但配置文件配置起来依然过于复杂&#xff0c;而我们接下来要…

虚拟机VMware的使用流程以及出现的问题附解决方法

虚拟机VMware的使用流程以及出现的问题附解决方法 下载安装 略。。。 创建虚拟机 虚拟机的设置如下&#xff1a;注意网络适配器为NAT 如果出现ip addr 命令&#xff1a;不显示IP地址的话&#xff1a; 解决方式如下&#xff1a; 首先设置网卡&#xff1a;先查看一下onboot是…

软件工程与计算总结(三)示例项目描述

本节介绍一个标准的项目描述&#xff0c;大家可以作为蓝本学习~ 目录 一.背景 二.目标 三.系统用户 四.用户访谈要点 1.收银员 2.客户经理 3.总经理 4.系统管理员 五.项目实践过程 一.背景 A是一家刚刚发展起来的小型连锁商店&#xff0c;其前身是一家独立的小百货门面…

贪心算法+练习

正值国庆之际&#xff0c;祝愿祖国繁荣昌盛&#xff0c;祝愿朋友一生平安&#xff01;终身学习&#xff0c;奋斗不息&#xff01; 目录 1.贪心算法简介 2.贪心算法的特点 3.如何学习贪心算法 题目练习&#xff08;持续更新&#xff09; 1.柠檬水找零&#xff08;easy&…

ES6中数组的扩展

1. 扩展运算符 用三个点(...)表示&#xff0c;它如同rest参数的逆运算&#xff0c;将数组转为用逗号分隔的参数序列。扩展就是将一个集合分成一个个的。 console.log(...[1, 2, 3]); // 1, 2, 3可以用于函数调用 扩展运算符后还可以放置表达式 ...(x > 0 ? [a] : [])如…

YOLOv2解析 | 批归一化 锚 主干网

文章目录 1 改进1.1 Batch Normalization 批归一化1.2 High Resolution Classifier 更高分辨率的分类器1.3 **Convolutional With Anchor Boxes 带锚盒的卷积**1.4 Dimension Clusters 维度集群1.5 更深更宽的主干网络1.6 Fine-Grained Features** **细粒度特征 **1.,7 Multi-S…

Altium Designer 批量添加元器件后缀

Altium Designer 批量添加元器件后缀 方法一方法二可能出现的问题要注意 方法一 您可以使用 Altium Designer 中的“批量修改元器件名称”功能来批量添加元器件后缀。具体步骤如下&#xff1a; 1.为了方便显示 操作流程&#xff0c;我这里复制了几个原理图的文件&#xff0c;粘…

剑指offer——JZ22 链表中倒数最后k个结点 解题思路与具体代码【C++】

一、题目描述与要求 链表中倒数最后k个结点_牛客题霸_牛客网 (nowcoder.com) 题目描述 输入一个长度为 n 的链表&#xff0c;设链表中的元素的值为 ai &#xff0c;返回该链表中倒数第k个节点。 如果该链表长度小于k&#xff0c;请返回一个长度为 0 的链表。 数据范围&…

好奇喵 | Surface Web ---> Deep Web ---> Dark Web

前言 我们可能听说过深网(deep Web)、暗网(dark Web)等名词&#xff0c;有些时候可能会认为它们是一个东西&#xff0c;其实不然&#xff0c;两者的区别还是比较大的。 什么是deep web&#xff1f; 深网是网络的一部分&#xff0c;与之相对应的是表层网络&#xff08;surface …

jsbridge实战2:Swift和h5的jsbridge通信

[[toc]] demo1: 文本通信 h5 -> app 思路&#xff1a; h5 全局属性上挂一个变量app 接收这个变量的内容关键API: navigation代理 navigationAction.request.url?.absoluteString // 这个变量挂载在 request 的 url 上 &#xff0c;在浏览器实际无法运行&#xff0c;因…

Spring事务

事务概念 逻辑上的一组操作&#xff0c;要么都成功、要么都失败 典型案例&#xff1a;银行转账 事务特性&#xff1a;ACID【原子、一致、隔离、持久】 搭建环境 银行转账操作 web&#xff1a; service&#xff1a;逻辑操作&#xff0c;调用dao dao&#xff1a;创建两个方法 …