GPT带我学-设计模式-10观察者模式
1 请你介绍一下观察者模式
观察者模式(Observer Pattern)是一种设计模式,它定义了对象之间的一对多依赖关系,当一个对象(被观察者)的状态发生改变时,所有依赖于它的对象(观察者)都会得到通知并自动更新。
这种模型主要由三个角色构成:
观察者(Observer):接收并处理被观察者发出的通知。通常,观察者需要定义一个更新函数,用以在接收到通知时更新自己的状态。
被观察者(Subject):当其状态发生改变时,它需要通知所有观察者。通常,被观察者维护一个观察者列表,并定义添加、删除和通知观察者的方法。
具体观察者(Concrete Observer)和具体被观察者(Concrete Subject):分别实现观察者和被观察者的接口,完成具体的业务逻辑。
观察者模式的主要优点是可以在不改变被观察者和观察者的情况下,实现两者之间的松耦合关系。当被观察者发生改变时,所有观察者都会得到通知并更新,非常适合处理一对多的关系。
典型的应用包括:GUI事件模型、订阅发布模型等。
2 观察者模式有几种类型
观察者模式一般分为两大类:拉模型和推模型。
拉模型:观察者将被观察者对象拉入自己进行处理,也就是说,观察者在接收到被观察者的变更通知后,需要主动调用获取所需信息。这种方式的优点是观察者可以根据需要决定是否调用,提高了灵活性。但是,如果被观察者的数据非常复杂,每个观察者需要的数据又不同,那么观察者在拉取数据的时候可能会感到困难。
推模型:被观察者主动向观察者推送信息,也就是说,被观察者在状态变化后,会把一些参数推送给观察者。这种方式的优点是观察者可以直接获取到更新的数据,实现方式相对简洁;但同时也失去了一些灵活性,因为被观察者已经决定了要推送的数据,观察者无法根据需要选择。
在真实的系统设计中,这两种模型具有各自的应用场景,可以根据实际需要选择使用
3 请用java写一个推模型观察者模式的例子
观察者模式是一种较为常用的设计模式,它定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
下面的例子展示了一个基本的观察者模式的实现,其中包含一个主题(Subject),两个观察者(Observer)和一个推送新闻的方法。主题变化时,所有的观察者都会接收到通知。
首先定义一个 Observable 接口,描绘被观察者的基本结构:
import java.util.ArrayList;
import java.util.List;public class NewsAgency {private String news;private List<Channel> channels = new ArrayList<>();public void registerChannel(Channel channel) {channels.add(channel);}public void unRegisterChannel(Channel channel) {channels.remove(channel);}public void setNews(String news) {this.news = news;for (Channel channel : channels) {channel.update(this.news);}}
}
定义一个 Observer 接口,代表观察者:
public interface Channel {void update(Object o);
}
最后,创建两个具体的 Observer 实现:
public class NewsChannel implements Channel {private String news;@Overridepublic void update(Object news) {this.news = (String) news;}
}
测试代码
public class Main {public static void main(String[] args) {// 创建新闻机构NewsAgency observable = new NewsAgency();// 创建新闻频道NewsChannel observer = new NewsChannel();// 新闻频道订阅新闻机构observable.registerChannel(observer);// 新闻机构发布新闻observable.setNews("Hello, Observer Pattern!");// 新闻频道接收到新闻更新String news = observer.getNews();System.out.println(news);}
}
在以上示例中,一旦 NewsAgency 设置新闻,所有注册的频道都会接收新闻更新。如果你在 NewsAgency 中添加更多的频道,它们也会在新消息可用时收到更新。
4 请用java观察者模式写一个订阅发布的例子
当然可以,以下是一个使用Java观察者模式实现的订阅发布示例:
首先,我们创建一个主题(Subject)接口,该接口包含了添加、删除观察者以及通知观察者的方法。
public interface Subject {void attach(Observer observer);void detach(Observer observer);void notifyObservers(String message);
}
接下来,我们实现该接口并为其添加一个消息列表,记录待发送的消息。
public class Newsletter implements Subject {private List<Observer> observers = new ArrayList<>();private List<String> messages = new ArrayList<>();@Overridepublic void attach(Observer observer) {observers.add(observer);}@Overridepublic void detach(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers(String message) {messages.add(message);for (Observer observer : observers) {observer.update(messages);}messages.clear();}
}
在这个实现中,我们维护了一个观察者列表和一个消息列表。每次调用notifyObservers()方法时,我们将新的消息添加到列表中,然后遍历观察者列表并调用每个观察者的update()方法,将消息列表作为参数传递给观察者。
最后,我们定义观察者(Observer)接口,并实现一个具体的观察者类,它将收到来自主题的消息。
public interface Observer {void update(List<String> messages);
}public class Subscriber implements Observer {private String name;public Subscriber(String name) {this.name = name;}@Overridepublic void update(List<String> messages) {System.out.printf("%s received %d messages.\n", name, messages.size());for (String message : messages) {System.out.printf("%s received message: %s\n", name, message);}}
}
在该实现中,我们实现了Observer接口并重写了update()方法,该方法将打印出我们接收到的所有消息。然后我们实现了一个具体的观察者类Subscriber,它包含一个名称字段,在构造函数中初始化该字段。
现在,我们可以测试我们的代码,创建一些订阅者并向他们发送一些消息:
public static void main(String[] args) {Newsletter newsletter = new Newsletter();Observer subscriber1 = new Subscriber("John");Observer subscriber2 = new Subscriber("Marry");newsletter.attach(subscriber1);newsletter.attach(subscriber2);newsletter.notifyObservers("Hello, subscribers!");newsletter.notifyObservers("How are you today?");newsletter.detach(subscriber1);newsletter.notifyObservers("Goodbye, subscribers!");
}
在这个示例中,我们创建了一个Newsletter对象作为主题,并创建了两个Subscriber对象作为观察者。我们将这两个观察者添加到主题中,并向他们发送一些消息。然后,我们从主题中删除第一个观察者,并再次向另一个观察者发送一条消息。
总之,这个示例演示了如何使用Java观察者模式创建一个基本的订阅发布系统。我们创建一个主题对象来管理所有的观察者,并允许观察者订阅或取消订阅主题的消息,同时也能够将消息广播给所有的观察者。
相关文章:
GPT带我学-设计模式-10观察者模式
1 请你介绍一下观察者模式 观察者模式(Observer Pattern)是一种设计模式,它定义了对象之间的一对多依赖关系,当一个对象(被观察者)的状态发生改变时,所有依赖于它的对象(观察者&…...
JDK - 常用的设计模式
单例模式 : Runtime 类:Java 运行时环境是单例的,可以通过 Runtime.getRuntime() 方法获得实例。Calendar 类:Calendar.getInstance() 方法返回的是一个单例的 Calendar 实例。数据源连接池:连接池的管理通常采用单例模…...
华为OD机考算法题:寻找最大价值的矿堆
题目部分 题目寻找最大价值的矿堆难度难题目说明给你一个由 0(空地)、1(银矿)、2(金矿)组成的的地图,矿堆只能由上下左右相邻的金矿或银矿连接形成。超出地图范围可以认为是空地。 假设银矿价值…...

wf-docker集群搭建(未完结)
系列文章目录 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 系列文章目录前言一、redis集群二、mysql集群三、nacos集群1. 环境要求2. 拉取镜像2.1. 拉取镜像方式配置集群2.2. 自定义nacos镜像配置集群 3 自定义…...
uni-app 在 APP 端的版本强制更新与热更新
整包更新与热更新的区别 ① 整包更新是指下载完整 apk 文件进行覆盖安装 ② 热更新是指把 app 有改动的地方打包进 wgt 文件,只更新 wgt 文件中的内容,不进行整包安装,在用户视角也叫做省流量更新 版本号规则约束 建议严格遵循 Semantic …...

实在智能受邀参加第14届珠中江数字化应用大会,AI赋能智能制造,共话“湾区经验”
制造业是实体经济的主体,是技术创新的主战场,是供给侧结构性改革的重要领域。抢占新一轮产业竞争制高点,制造业的数字化转型已成为行业升级的必由之路。 10月21日,第14届“珠中江”(珠海、中山、江门)数字…...
Qt 窗口的尺寸
默认尺寸 对于一个Qt的窗口(继承于QWidget),获取其窗体尺寸的方法size(); 以一个Qt创建Qt Widgets Application项目的默认生成代码为基础,做如下测试 MainWindow::MainWindow(QWidget *parent): QMainWindow(parent…...

游戏数据分析对于运营游戏平台的重要性
游戏数据分析对于运营游戏平台具有至关重要的意义,它可以提供深入的见解,帮助了解玩家行为、偏好和互动,从而优化游戏体验,提高玩家参与度和留存率。 首先,通过游戏数据分析,运营者可以了解玩家在游戏中的表…...

微信群发消息的正确打开方式,让你的社交更高效!
在当今的社交媒体时代,微信已经成为了我们生活中必不可少的一部分。而微信的群发消息功能,让我们可以方便地将信息一次性发送给多个联系人。然而,微信的群发消息功能有一个限制,即每次只能群发200个联系人。这对于需要发送消息给大…...

HTML5语义化标签 header 的详解
🌟🌟🌟 专栏详解 🎉 🎉 🎉 欢迎来到前端开发之旅专栏! 不管你是完全小白,还是有一点经验的开发者,在这里你会了解到最简单易懂的语言,与你分享有关前端技术和…...

SpringCloud复习:(2)@LoadBalanced注解的工作原理
LoadBalanced注解标记了一个RestTemplate或WebClient bean使用LoadBalancerClient来进行负载均衡。 LoadBalancerAutoConfiguration类给带注解的RestTemplate添加了拦截器:LoadBalancerInterceptor. 具体流程如下: 首先定义一个LoadBalancerInterceptor…...
vue钩子函数以及例子
Vue.js 是一个基于组件化的前端框架,它提供了一些钩子函数,用于控制组件在不同阶段的行为和处理。以下是 Vue.js 常用的钩子函数以及它们的作用和示例: beforeCreate:在实例被创建之前调用。此时组件的数据、方法等还没有被初始化…...

redis场用命令及其Java操作
目录 1. Redis入门 1.1 Redis简介 1.2 Redis下载与安装 1.2.1 Redis下载 1.2.2 Redis安装 1.3 Redis服务启动与停止 1.3.1 服务启动命令 1.3.2 客户端连接命令 1.3.3 修改Redis配置文件 1.3.4 Redis客户端图形工具 2. Redis数据类型 2.1 五种常用数据类型介绍 2.2 …...

UG\NX二次开发 同时设置多个对象的高亮状态 UF_DISP_set_highlights
文章作者:里海 来源网站:王牌飞行员_里海_里海NX二次开发3000例,里海BlockUI专栏,C\C++-CSDN博客 感谢粉丝订阅 感谢 captainliubang 订阅本专栏,非常感谢。 简介 UG\NX二次开发 同时设置多个对象的高亮状态 UF_DISP_set_highlights 效果 代码(在for循环中逐个设置多个对象…...
Qt+树莓派4B 手动设置系统日期和时间
文章目录 前言一、设置日期二、设置时间 前言 某些设备需要在无网络环境下工作,系统时间和日期无法通过网络实时同步,此时就需要人为设置. 一、设置日期 QString m_date,m_time;QDateEdit *dateEdit new QDateEdit(this); dateEdit->setFixedSize(250,60); connect(date…...
用大顶堆和小顶堆实现优先队列
大顶堆小顶堆(或大根堆小根堆) 利用大顶堆实现优先队列,所谓大顶堆,容器内部元素是有序的,而且是按从大到小排序的(小顶堆刚好相反,从小到大)。容器只有一个出口一个入口࿰…...

PDCA项目开发环境搭建说明
PDCA项目开发环境搭建说明 环境准备 JDK 15.0 ; IDEA Community Edition 2021.3 版本要对应,不然会报错 Jdk 安装步骤:https://blog.csdn.net/qq_34913677/article/details/108894727 IDea 安装说明:https://blog.csdn.net/dream…...

Git简明教程
1.Git的定位 在我们自己开发项目的过程中,经常会遇到这样的情况,为了防止代码丢失,或者新变更的代码影响到原有的代码功能,为了在失误后能恢复到原来的版本,不得不复制出一个副本,比如:“坦克大战1.0”“坦…...
数据结构顺序表(C语言版)
目录 1.实现的接口及其功能2.代码块 1.实现的接口及其功能 //初始化顺序表void initSL(SL* p); //销毁顺序表 void DestorySL(SL* p); //头插 void PushFont(SL* p, SeqListType x); //尾插 void PushBack(SL* p, SeqListType x); //头删 void PopFont(SL* p); //尾删 void Pop…...

新手如何备考学习PMP?
一、PMP学习7步走攻略 1、熟悉考试大纲: PMP考试大纲是备考的基础,考生需要详细熟悉考试大纲,了解各个知识领域的重点和难点。 2、制定学习计划: 根据考试大纲和个人情况,制定学习计划,合理分配学习时间…...

【Linux】Ubuntu 创建应用图标的方式汇总,deb/appimage/通用方法
Ubuntu 创建应用图标的方式汇总,deb/appimage/通用方法 对于标准的 Ubuntu(使用 GNOME 桌面),desktop 后缀的桌面图标文件主要保存在以下三个路径: 当前用户的桌面目录(这是最常见的位置)。所…...
vue.js not detected解决方法
如果你在开发环境中遇到“Vue.js not detected”的错误,这通常意味着你的项目没有正确设置或者配置以识别Vue.js。下面是一些解决这个问题的步骤: 1. 确认Vue.js已正确安装 首先,确保你的项目中已经正确安装了Vue.js。你可以通过以下命令来…...

ORACLE 修改端口号之后无法启动?
Oracle数据库更改端口后出现监听器无法启动的问题确实较为常见,但并非必然发生。这一问题通常源于配置错误或环境冲突,而非端口修改本身。以下是系统性解决方案: 🔍 一、问题根源分析 配置文件语法错误 修…...

agent基础概念
agent是什么 我个人认为agent并没有一个所谓完美的定义,它是一个比较活的概念,就像是你眼中的一个机器人你希望它做什么事,和我眼中的机器人它解决事情的流程,其实是可以完全不同的,没有必要非得搞一个统一的概念或流程来概况它。但我们依然可以概况几个通用的词来描述它…...

华为云Flexus+DeepSeek征文 | 基于DeepSeek-V3构建企业知识库问答机器人实战
作者简介 我是摘星,一名专注于云计算和AI技术的开发者。本次通过华为云MaaS平台体验DeepSeek系列模型,将实际使用经验分享给大家,希望能帮助开发者快速掌握华为云AI服务的核心能力。 目录 作者简介 1. 引言 2. 技术选型与架构设计 2.1 技…...
【汇编逆向系列】七、函数调用包含多个参数之浮点型- XMM0-3寄存器
目录 1. 汇编代码 1.1 debug编译 1.2 release编译 2. 汇编分析 2.1 浮点参数传递规则 2.2 栈帧rsp的变化时序 2.3 参数的访问逻辑 2.4 返回值XMM0寄存器 3. 汇编转化 3.1 Debug编译 3.2 Release 编译 3.3 C语言转化 1. 汇编代码 上一节介绍了整型的函数传参&#x…...

设备驱动与文件系统:06 目录与文件
磁盘使用的最后一层抽象:文件系统 今天我们讲第31讲,这一讲将完成磁盘对磁盘使用的最后一层抽象。对此板使用最后一层抽象,抽象出来的是什么呢? 实际上我们使用过磁盘,大家应该有这样的认识,最后不管这个磁…...

【MySQL系列】MySQL 导出表数据到文件
博客目录 一、使用 SELECT INTO OUTFILE 语句基本语法参数详解注意事项实际示例 二、使用 mysqldump 工具基本语法常用选项实际示例 三、使用 MySQL Workbench 导出导出步骤高级选项 四、其他导出方法1. 使用 mysql 命令行客户端2. 使用 LOAD DATA INFILE 的逆向操作3. 使用编程…...

【统计方法】树模型,ensemble,bagging, boosting
决策树基础 回归树 理论上,决策区域可以有任何形状。• 然而,我们选择将预测空间划分为高维矩形或框,这是为了简单和易于解释结果预测模型 目标:将预测空间划分为矩形区域,最小化残差平方和(RSS&#x…...

如何使用Jmeter进行压力测试?
🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 一、什么是压力测试 软件测试中:压力测试(Stress Test),也称为强度测试、负载测试。压力测试是模拟实际应用的软硬…...