观察者模式 (Observer Pattern)

文章目录

      • 观察者模式 (Observer Pattern)
      • 原理
      • 优点
      • 缺点
      • 示例代码
        • 场景描述
        • 1. 定义观察者接口
        • 2. 定义目标接口
        • 3. 实现具体目标类
        • 4. 实现具体观察者类
        • 5. 客户端代码
        • 输出结果
      • UML 类图
      • 使用场景
      • 优化与扩展
      • 小结

观察者模式 (Observer Pattern)

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


原理

  1. 核心思想
    • 当目标对象(Subject)发生变化时,通知所有观察者(Observer)。
    • 将目标与观察者之间的依赖关系分离,使得两者可以独立变化。
  2. 适用场景
    • 一个对象的变化需要通知其他对象。
    • 不希望目标对象和观察者之间存在紧耦合关系。
  3. 参与角色
    • Subject(目标/被观察者)
      • 保存观察者对象的列表。
      • 提供注册、移除观察者的方法。
      • 当状态发生改变时,通知所有观察者。
    • Observer(观察者)
      • 提供更新接口,供目标调用。
    • ConcreteSubject(具体目标)
      • 实现具体的状态逻辑。
    • ConcreteObserver(具体观察者)
      • 实现更新接口,定义具体更新行为。

优点

  1. 解耦:观察者和目标分离,可以独立扩展。
  2. 动态响应:目标状态变化时,观察者可以动态收到通知。
  3. 复用性强:观察者模式非常灵活,适用于各种场景。

缺点

  1. 通知机制复杂性:通知过程可能产生较高的时间开销。
  2. 可能出现循环依赖:当观察者也会触发目标变化时,需防止死循环。
  3. 难以控制通知顺序:观察者的调用顺序由实现决定。

示例代码

场景描述

以新闻发布系统为例,新闻发布者是目标,订阅用户是观察者。当新闻发布时,所有订阅用户都会收到通知。


1. 定义观察者接口
// 观察者接口
public interface Observer {void update(String message); // 接收目标的更新通知
}

2. 定义目标接口
// 目标接口
public interface Subject {void registerObserver(Observer observer); // 注册观察者void removeObserver(Observer observer);   // 移除观察者void notifyObservers();                   // 通知所有观察者
}

3. 实现具体目标类
import java.util.ArrayList;
import java.util.List;// 具体目标类
public class NewsPublisher implements Subject {private List<Observer> observers; // 保存观察者列表private String news;              // 新闻内容public NewsPublisher() {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(news); // 通知每个观察者}}// 更新新闻并通知观察者public void setNews(String news) {this.news = news;notifyObservers();}
}

4. 实现具体观察者类
// 具体观察者
public class Subscriber implements Observer {private String name;public Subscriber(String name) {this.name = name;}@Overridepublic void update(String message) {System.out.println(name + " received news: " + message);}
}

5. 客户端代码
public class ObserverPatternExample {public static void main(String[] args) {NewsPublisher publisher = new NewsPublisher();// 创建观察者Observer alice = new Subscriber("Alice");Observer bob = new Subscriber("Bob");Observer charlie = new Subscriber("Charlie");// 注册观察者publisher.registerObserver(alice);publisher.registerObserver(bob);// 发布新闻publisher.setNews("Breaking News: Observer Pattern Explained!");// 移除观察者publisher.removeObserver(alice);// 再次发布新闻publisher.setNews("Update: Observer Pattern is Easy!");}
}

输出结果
Alice received news: Breaking News: Observer Pattern Explained!
Bob received news: Breaking News: Observer Pattern Explained!
Bob received news: Update: Observer Pattern is Easy!

UML 类图

        +------------------+|    Subject       |<-------------------++------------------+                    || + registerObserver()|                 || + removeObserver()  |                 || + notifyObservers() |                 |+------------------+                    |^                               ||                               |
+-----------------------+       +-----------------------+
|   NewsPublisher       |       |       Observer        |
+-----------------------+       +-----------------------+
| - observers : List    |       | + update(message)     |
| + setNews(news)       |       +-----------------------+
| + notifyObservers()   |                 ^
+-----------------------+                 ||                         |+-----------------------+   +-----------------------+|      Subscriber        |   |      Subscriber        |+-----------------------+   +-----------------------+| - name : String        |   | - name : String        || + update(message)      |   | + update(message)      |+-----------------------+   +-----------------------+

使用场景

  1. 事件监听:GUI 开发中,按钮点击事件的监听。
  2. 消息订阅:发布/订阅模式,如 RabbitMQ、Kafka。
  3. 实时更新:如股票价格、天气更新。

优化与扩展

  1. 使用 Java 内置类
    • Java 提供了 Observable 类和 Observer 接口。
    • Observable 已被标记为过时,推荐自定义实现。
  2. 多线程支持
    • 使用线程安全的集合 CopyOnWriteArrayList 避免并发问题。
  3. 结合其他模式
    • 中介者模式 结合,简化复杂的观察者关系。

小结

  • 观察者模式在事件驱动系统中非常常用。
  • 它解耦了目标和观察者,但需要注意性能问题。
  • 可结合其他模式(如工厂模式)简化观察者的管理和创建。

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

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

相关文章

从零开始学 Maven:简化 Java 项目的构建与管理

一、关于Maven 1.1 简介 Maven 是一个由 Apache 软件基金会开发的项目管理和构建自动化工具。它主要用在 Java 项目中&#xff0c;但也可以用于其他类型的项目。Maven 的设计目标是提供一种更加简单、一致的方法来构建和管理项目&#xff0c;它通过使用一个标准的目录布局和一…

去哪儿大数据面试题及参考答案

Hadoop 工作原理是什么&#xff1f; Hadoop 是一个开源的分布式计算框架&#xff0c;主要由 HDFS&#xff08;Hadoop 分布式文件系统&#xff09;和 MapReduce 计算模型两部分组成 。 HDFS 工作原理 HDFS 采用主从架构&#xff0c;有一个 NameNode 和多个 DataNode。NameNode 负…

守护进程

目录 守护进程 前台进程 后台进程 session&#xff08;进程会话&#xff09; 前台任务和后台任务比较好 本质 绘画和终端都关掉了&#xff0c;那些任务仍然在 bash也退了&#xff0c;然后就托孤了 ​编辑 守护进程化---不想受到任何用户登陆和注销的影响​编辑 如何…

element ui select绑定的值是对象的属性时,显示异常.

需要声明 value-key"value". el-select v-model"value" clearable placeholder"Select" value-key"value" style"width: 240px"><!-- <el-option v-for"item in options" :key"item.value" :…

SAAS美容美发系统架构解析

随着技术的不断发展&#xff0c;SAAS&#xff08;Software as a Service&#xff0c;软件即服务&#xff09;模式在各个行业的应用逐渐深化&#xff0c;美容美发行业也不例外。传统的美容美发店面通常依赖纸质记录、手动操作和复杂的管理流程&#xff0c;而随着SAAS平台的出现&…

[代码随想录Day24打卡] 93.复原IP地址 78.子集 90.子集II

93.复原IP地址 一个合法的IP地址是什么样的&#xff1a; 有3个’.分割得到4个数&#xff0c;每个数第一个数不能是0&#xff0c;不能含有非法字符&#xff0c;不能大于255。 这个是否属于合法IP相当于一个分割问题&#xff0c;把一串字符串分割成4部分&#xff0c;分别判断每…

Java学习笔记--继承方法的重写介绍,重写方法的注意事项,方法重写的使用场景,super和this

目录 一&#xff0c;方法的重写 二&#xff0c;重写方法的注意事项 三&#xff0c;方法重写的使用场景 四&#xff0c;super和this 1.继承中构造方法的特点 2.super和this的具体使用 super的具体使用 this的具体使用 一&#xff0c;方法的重写 1.概述:子类中有一个和父类…

gRPC 双向流(Bidirectional Streaming RPC)的使用方法

gRPC 是一个支持多种语言的高性能 RPC 框架&#xff0c;拥有丰富的 API 来简化服务端和客户端的开发过程。gRPC 支持四种 RPC 类型&#xff1a;Unary RPC、Server Streaming RPC、Client Streaming RPC 和 Bidirectional Streaming RPC。下面是双向流 API 的使用方法。 双向流…

npm install -g@vue/cli报错解决:npm error code ENOENT npm error syscall open

这里写目录标题 报错信息1解决方案 报错信息2解决方案 报错信息1 使用npm install -gvue/cli时&#xff0c;发生报错&#xff0c;报错图片如下&#xff1a; 根据报错信息可以知道&#xff0c;缺少package.json文件。 解决方案 缺什么补什么&#xff0c;这里我们使用命令npm…

【ComfyUI】前景分割ComfyUI-BiRefNet-Hugo (无法选定分割的主体,背景鉴别由模型数据,也叫二分分割,显著性分割)

源码&#xff1a;https://github.com/ZhengPeng7/BiRefNet comfyui插件&#xff1a;https://github.com/MoonHugo/ComfyUI-BiRefNet-Hugo 模型下载地址&#xff1a;https://huggingface.co/ZhengPeng7/BiRefNet 工作流以及相关资源下载&#xff1a;https://pan.baidu.com/s/1-U…

大数据技术之Spark :我快呀~

在 MapReduce 为海量数据的计算服务多年后&#xff0c;随着时代的发展和 Spark 等新技术的出现&#xff0c;它的劣势也慢慢的凸显出来了&#xff1a; 执行速度慢。编程复杂度过高。 先看第一点 2000 年代诞生的 MapReduce &#xff0c;因为计算资源有限&#xff0c;所以 Map…

新160个crackme - 105-royalaccezzcrackme

运行分析 需破解Name和Serial&#xff0c;点击OK没反应 PE分析 ASM程序&#xff0c;32位&#xff0c;无壳 静态分析&动态调试 ida找到关键字符串 进行静态分析&#xff0c;逻辑如下&#xff1a;1、Name长度大于4&#xff0c;小于212、fun_1返回值为1 对func_1进行动态调试分…

【RISC-V CPU 专栏 -- 香山处理器介绍】

文章目录 RISC-V 香山处理器介绍雁栖湖处理器南湖处理器RISC-V 香山处理器介绍 相信很多小伙伴对于“香山”都不陌生,它是一款开源RISC-V处理器核,香山的每一代架构,都是采用了湖的名字,第一代架构被命名为雁栖湖,第二代架构则叫做 “南湖”。 “雁栖湖”这款处理器的 R…

远程视频验证如何改变商业安全

如今&#xff0c;商业企业面临着无数的安全挑战。尽管企业的形态和规模各不相同——从餐厅、店面和办公楼到工业地产和购物中心——但诸如入室盗窃、盗窃、破坏和人身攻击等威胁让安全主管时刻保持警惕。 虽然传统的监控摄像头网络帮助组织扩大了其态势感知能力&#xff0c;但…

【TQ2440】02 串口连接进入u-boot

需要收到的板子已经烧写好系统或u-boot&#xff0c;看开机液晶屏底下的四个LED灯有没有亮黄绿色&#xff0c;没有就是还没烧写u-boot&#xff0c;需要先使用Jlink烧写u-boot 进入 uboot 的下载模式&#xff0c;如果从 Nor Flash 启动默认的就是进入 uboot 的下载模式&#xff…

QCommandLinkButton控件 全面详解

本系列文章全面的介绍了QT中的57种控件的使用方法以及示例,包括 Button(PushButton、toolButton、radioButton、checkBox、commandLinkButton、buttonBox)、Layouts(verticalLayout、horizontalLayout、gridLayout、formLayout)、Spacers(verticalSpacer、horizontalSpacer)、…

【Vue】Ego商城项目跟做

技术栈 Vue全家桶&#xff1a;Vue VueRouter Vuex Axios ElementUI 依赖安装 网络请求&#xff1a;npm install --save axios --no-fund Element&#xff1a;vue add element 后端相关依赖&#xff1a;npm install --save express cors mysql --no-fund token&#xff1a;np…

python简单算法

冒泡 def boll(lis):i 0while i<len(lis)-1:j 0while j<len(lis)-1-i:if lis[j] > lis[j1]:lis[j],lis[j 1] lis[j1],lis[j]j1i1选择排序 def selct1(lit):i 0while i<len(lit)-1:j i1min1 iwhile j < len(lit):if lit[j] < lit[min1]:min1 jj 1li…

2024年第15届蓝桥杯C/C++组蓝桥杯JAVA实现

目录 第一题握手&#xff0c;这个直接从49累加到7即可&#xff0c;没啥难度&#xff0c;后面7个不握手就好了&#xff0c;没啥讲的&#xff0c;(然后第二个题填空好难&#xff0c;嘻嘻不会&#xff09; 第三题.好数​编辑 第四题0R格式 宝石组合 数字接龙 最后一题:拔河 第…

【Docker】常用命令汇总

Docker 是1个开源的应用容器引擎&#xff0c;基于Go 语言并遵从 Apache2.0 协议开源。 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。 容器是完全使用沙箱机制&#xff0c;相…