14 设计模式值观察者模式(书籍发布通知案例)

一、观察者模式定义

        在日常开发中,我们经常会遇到一种场景:某个对象的状态发生变化时,需要通知并更新其他相关对象。这时,观察者模式便成为了解决问题的有效方案。观察者模式是一种常见的设计模式,它允许一个对象的状态变化自动通知依赖于它的其他对象。

        观察者模式(Observer Pattern)是一种行为型设计模式,定义了对象间的一对多依赖关系,使得每当一个对象的状态发生变化时,所有依赖于它的对象都会自动收到通知并更新。

        换句话说,观察者模式允许一个对象(称为被观察者)将其状态的变化推送给多个观察者(观察者),而观察者则根据状态变化做出相应的处理。


二、观察者模式组成

观察者模式包含以下几个重要组成部分:

1.Subject(主题/被观察者)

        被观察者是状态变化的源头,它会维护一组观察者对象。

        被观察者提供接口让观察者注册、注销,并在状态发生变化时通知观察者。

2.Observer(观察者)

        观察者是依赖于被观察者的对象,当被观察者的状态发生变化时,观察者会接收到通知并做出相应的处理。

        观察者接口通常定义一个 update 方法,用于接受通知。

3.ConcreteSubject(具体被观察者)

        具体被观察者实现了 Subject 接口,并在状态变化时通知所有已注册的观察者。

4.ConcreteObserver(具体观察者)

        具体观察者实现了 Observer 接口,并在接收到通知时更新自身的状态。


三、观察者模式的工作原理

        在观察者模式中,被观察者通过 register 方法注册多个观察者。被观察者的状态一旦发生变化,调用 notify 方法将通知所有已注册的观察者,观察者会通过 update 方法接收并处理这些变化。


四、案例讲解:书籍发布通知

        为了更好地理解观察者模式,下面我们通过一个书籍发布通知的例子来演示观察者模式的实际应用。

1. 设计接口与类

        在本例中,我们将书籍发布看作是被观察者,而读者则是观察者。当新书发布时,我们需要通知所有注册的读者,告诉他们新书的名字。

(1)Observer 接口

public interface Observer {void update(String bookName);
}

  Observer 接口定义了一个 update 方法,用于接收新书发布的通知,并通过书名来更新观察者的状态。

(2)ConcreteObserver

public class ConcreteObserver implements Observer {private String readerName;public ConcreteObserver(String readerName) {this.readerName = readerName;}@Overridepublic void update(String bookName) {System.out.println(readerName + ", 收到新书发布通知:" + bookName);}
}

  ConcreteObserver 是具体的观察者类,它保存读者的姓名,并在接收到新书发布通知时,输出一条消息来告诉读者。

(3)Subject 接口

public interface Subject {void registerObserver(Observer observer);  // 注册观察者void removeObserver(Observer observer);    // 移除观察者void notifyObservers();                    // 通知观察者
}

  Subject 接口定义了三个方法:注册观察者、移除观察者和通知所有观察者。

(4)ConcreteSubject

public class ConcreteSubject implements Subject {private List<Observer> observers;private String bookName;public ConcreteSubject() {observers = new ArrayList<>();}@Overridepublic void registerObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(bookName);}}// 新书发布方法,更新书名并通知所有观察者public void publishBook(String bookName) {this.bookName = bookName;notifyObservers();}
}

  ConcreteSubject 类实现了 Subject 接口。它维护一个观察者列表,并在新书发布时通知所有已注册的观察者。

2.测试类

public class TestObserverPattern {public static void main(String[] args) {ConcreteSubject bookPublisher = new ConcreteSubject();Observer reader1 = new ConcreteObserver("Theodore_1022");Observer reader2 = new ConcreteObserver("Andy");Observer reader3 = new ConcreteObserver("小胖");bookPublisher.registerObserver(reader1);bookPublisher.registerObserver(reader2);bookPublisher.registerObserver(reader3);System.out.println("发布新书:超越音符");bookPublisher.publishBook("超越音符");bookPublisher.removeObserver(reader2);System.out.println("发布新书:记得");bookPublisher.publishBook("记得");}
}

3. 运行输出

发布新书:超越音符
Theodore_1022, 收到新书发布通知:超越音符
Andy, 收到新书发布通知:超越音符
小胖, 收到新书发布通知:超越音符

发布新书:记得
Theodore_1022, 收到新书发布通知:记得
小胖, 收到新书发布通知:记得


五、观察者模式的优缺点

1.优点

  • 松耦合:观察者模式将观察者与被观察者解耦。被观察者不需要知道观察者的具体实现,只需要调用 update 方法。
  • 动态更新:可以动态地添加或删除观察者,系统可以根据需要进行扩展。
  • 适用于一对多的场景:当一个对象的状态变化需要同时影响多个对象时,观察者模式是理想的选择。

2.缺点

  • 通知过多:当观察者较多时,通知会影响性能。如果被观察者频繁发生变化,可能会引发性能问题。
  • 依赖过度:观察者模式会导致观察者过于依赖被观察者的实现,可能会影响代码的灵活性。

六、总结

        观察者模式是一种非常适合“一对多”场景的设计模式。在需要解耦的场景中,它为对象之间的通信提供了灵活、低耦合的方式。本次案例中,我们通过“书籍发布”的实际例子,清晰地展示了如何实现观察者模式,并将模式的各个组成部分一一拆解。

        通过实现观察者模式,我们能够在系统中自动管理对象间的依赖关系,确保在状态变化时,系统能够自动进行更新,而无需手动干预。这使得代码的扩展性和可维护性得到了显著提升。

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

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

相关文章

15分钟训练数字人MimicTalk

只需15分钟&#xff0c;就能训练高质量&#xff0c;个性化数字人大模型。由浙江大学与字节跳动联合推出MimicTalk算法&#xff0c;目前已开源。 在外表和说话风格上和真人相似。将通用3D数字人大模型适应到单个目标人&#xff0c;采用动静结合的高效微调方案&#xff0…

c++高级篇(四) ——Linux下IO多路复用之epoll模型

IO多路复用 —— epoll 前言 在之前我们就已经介绍过了select和poll,在作为io多路复用的最后一个的epoll,我们来总结一下它们之间的区别: a select 实现原理 select 通过一个文件描述符集合&#xff08;fd_set&#xff09;来工作&#xff0c;该集合可以包含需要监控的文件…

【kettle】mysql数据抽取至kafka/消费kafka数据存入mysql

目录 一、mysql数据抽取至kafka1、表输入2、json output3、kafka producer4、启动转换&#xff0c;查看是否可以消费 二、消费kafka数据存入mysql1、Kafka consumer2、Get records from stream3、字段选择4、JSON input5、表输出 一、mysql数据抽取至kafka 1、表输入 点击新建…

docker-compose部署skywalking 8.1.0

一、下载镜像 #注意 skywalking-oap-server和skywalking java agent版本强关联&#xff0c;版本需要保持一致性 docker pull elasticsearch:7.9.0 docker pull apache/skywalking-oap-server:8.1.0-es7 docker pull apache/skywalking-ui:8.1.0二、部署文件docker-compose.yam…

用Python开发一个经典贪吃蛇小游戏

Python 是开发小游戏的绝佳工具,借助第三方库,如 pygame,我们可以快速开发一个经典的贪吃蛇游戏。本篇将介绍如何用 Python 实现一个完整的贪吃蛇小游戏。 一、游戏设计 1.1 游戏规则 玩家通过方向键控制贪吃蛇移动。贪吃蛇吃到食物后会变长,同时得分增加。如果贪吃蛇撞到…

在 MacOS 上为 LM Studio 更换镜像源

在 MacOS 之中使用 LM Studio 部署本地 LLM时&#xff0c;用户可能会遇到无法下载模型的问题。 一般的解决方法是在 huggingface.co 或者国内的镜像站 hf-mirror.com 的项目介绍卡页面下载模型后拖入 LM Studio 的模型文件夹。这样无法利用 LM Studio 本身的搜索功能。 本文将…

vue中.sync修饰符的用法

一、什么是.sync修饰符 在Vue.js中&#xff0c;.sync 修饰符用于创建一个双向绑定的 prop。它使子组件能够更新父组件的 prop 值&#xff0c;实现父子组件之间的双向数据同步。具体来说&#xff0c;.sync 修饰符主要有以下几个功能&#xff1a; 简化双向绑定&#xff1a; 使用…

【附源码】基于环信鸿蒙IM SDK实现一个聊天Demo

项目背景 本项目基于环信IM 鸿蒙SDK 打造的鸿蒙IM Demo&#xff0c;完全适配HarmonyOS NEXT系统&#xff0c;实现了发送消息&#xff0c;添加好友等基础功能。代码开源&#xff0c;功能简洁&#xff0c;如果您有类似开发需求可以参考。 源码地址&#xff1a;https://github.c…

SHELL----正则表达式

一、文本搜索工具——grep grep -参数 条件 文件名 其中参数有以下&#xff1a; -i 忽略大小写 -c 统计匹配的行数 -v 取反&#xff0c;不显示匹配的行 -w 匹配单词 -E 等价于 egrep &#xff0c;即启用扩展正则表达式 -n 显示行号 -rl 将指定目录内的文件打…

Can‘t find variable: token(token is not defined)

文章目录 例子 1&#xff1a;使用 var例子 2&#xff1a;使用 let 或 const例子 3&#xff1a;异步操作你的代码中的情况 Cant find variable: tokentoken is not defined源代码 // index.jsPage({data: {products:[],cardLayout: grid, // 默认卡片布局为网格模式isGrid: tr…

Kafka-创建topic源码

一、命令创建topic kafka-topics --create --topic quickstart-events --bootstrap-server cdh1:9092 --partitions 2 --replication-factor 2 二、kafka-topics脚本 exec $(dirname $0)/kafka-run-class.sh org.apache.kafka.tools.TopicCommand "$" 脚本中指定了…

【AI系统】GhostNet 系列

GhostNet 系列 本文主要会介绍 GhostNet 系列网络&#xff0c;在本文中会给大家带来卷积结构的改进方面的轻量化&#xff0c;以及与注意力(self-attention)模块的进行结合&#xff0c;部署更高效&#xff0c;更适合移动计算的 GhostNetV2。让读者更清楚的区别 V2 与 V1 之间的…

传奇996_51——脱下装备,附加属性设为0

奶奶的lua怎么都修改不了&#xff0c;可以调用txt的 ; LINKPICKUPITEM ; ChangeitemaddvaLue -1 5 0 ; GETITEMADDVALUE 3 5 M10 ; SENDUPGRADEITEM ; SENDMSG 9 你的衣服附加了<$STR(M10)>点防御属性. 或者lua callscriptex(actor,“LINKPICKUPITEM”) callscriptex(…

YOLOv8改进,YOLOv8引入CARAFE轻量级通用上采样算子,助力模型涨点

摘要 CARAFE模块的设计目的是在不增加计算复杂度的情况下,提升特征图的质量,特别是在视频超分辨率任务中,提升图像质量和细节。CARAFE结合了上下文感知机制和聚合特征的能力,通过动态的上下文注意力机制来提升细节恢复的效果。 理论介绍 传统的卷积操作通常依赖于局部区域…

大型制造企业IT蓝图、信息化系统技术架构规划与实施路线方案

关注 获取ppt​​​​​​全文&#xff0c;请关注作者

HTTP 长连接(HTTP Persistent Connection)简介

HTTP长连接怎么看&#xff1f; HTTP 长连接&#xff08;HTTP Persistent Connection&#xff09;简介 HTTP 长连接&#xff08;Persistent Connection&#xff09;是 HTTP/1.1 的一个重要特性&#xff0c;它允许在一个 TCP 连接上发送多个 HTTP 请求和响应&#xff0c;而无需为…

MySQL悲观锁和乐观锁

MySQL悲观锁和乐观锁 在数据库中&#xff0c;锁是用来管理并发控制的一种机制&#xff0c;确保数据的一致性和完整性。MySQL中的悲观锁和乐观锁是两种不同的并发控制策略&#xff0c;它们在处理并发事务时采用不同的方法。 悲观锁&#xff08;Pessimistic Locking&#xff09…

控制模组进入飞行模式

控制模组进入飞行模式 控制模组进入飞行模式 控制模组进入飞行模式 控制模组进入飞行模式 #!/bin/bash ## 5G模组采用USB3.0与上位机连接&#xff0c;usb接口在上位机上虚拟出多个port,其中一个可用于发送AT命令&#xff0c;控制模组 ## 本脚本控制模组进入飞行模式## flyin …

001集—— 创建一个WPF项目 ——WPF应用程序入门 C#

本例为一个WPF应用&#xff08;.NET FrameWork&#xff09;。 首先创建一个项目 双击xaml文件 双击xaml文件进入如下界面&#xff0c;开始编写代码。 效果如下&#xff1a; 付代码&#xff1a; <Window x:Class"WpfDemoFW.MainWindow"xmlns"http://schema…

微信小程序配置less并使用

1.在VScode中下载Less插件 2.在微信小程序中依次点击如下按钮 选择 从已解压的扩展文件夹安装… 3.选中刚在vscode中下载安装的插件文件 如果没有修改过插件的安装目录&#xff0c;一般是在c盘下C:\用户\用户名.vscode\extensions\mrcrowl.easy-less-2.0.2 我的路径是&#xf…