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、制定学习计划: 根据考试大纲和个人情况,制定学习计划,合理分配学习时间…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...

IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...

如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...