【面试题】什么是观察者模式?一般用在什么场景?

一、什么是观察者模式?

想象一下微信群聊

  • 你发一条消息(发布事件)
  • 群里所有人都收到了通知(观察者被触发)
  • 有些人回复,有些人点赞,有些人潜水(不同的反应)

这就是观察者模式一个对象(被观察者)的状态变化,会通知所有依赖它的对象(观察者)

二、Java代码示例:明星出轨爆料现场 🎬

import java.util.*; // 1. 观察者接口(吃瓜群众) interface GossipObserver { void update(String celebrityName, String scandal); } // 2. 具体观察者:不同反应的人 class ExcitedFan implements GossipObserver { private String name; public ExcitedFan(String name) { this.name = name; } @Override public void update(String celebrityName, String scandal) { System.out.println(name + "兴奋地尖叫:OMG!" + celebrityName + "竟然" + scandal + "!"); System.out.println(" → 立刻打开微博准备吃瓜🍉\n"); } } class CalmJournalist implements GossipObserver { @Override public void update(String celebrityName, String scandal) { System.out.println("记者冷静地记录:"); System.out.println(" 【独家爆料】" + celebrityName + "被曝" + scandal); System.out.println(" → 开始写新闻稿📰\n"); } } class IndifferentPerson implements GossipObserver { @Override public void update(String celebrityName, String scandal) { System.out.println("路人甲瞥了一眼:"); System.out.println(" " + celebrityName + "?不认识。关我屁事🙄"); System.out.println(" → 继续刷抖音\n"); } } // 3. 主题/被观察者接口(八卦中心) interface GossipSubject { void addObserver(GossipObserver observer); // 添加吃瓜群众 void removeObserver(GossipObserver observer); // 移除吃瓜群众 void notifyObservers(); // 发布八卦 } // 4. 具体主题:明星八卦 class CelebrityScandal implements GossipSubject { private String celebrityName; private String scandal; private List<GossipObserver> observers = new ArrayList<>(); public CelebrityScandal(String name) { this.celebrityName = name; } // 明星有新瓜了! public void newScandal(String scandal) { this.scandal = scandal; System.out.println("⚡⚡⚡ 狗仔队拍到:" + celebrityName + " " + scandal + "!"); System.out.println("八卦开始传播...\n"); notifyObservers(); // 通知所有吃瓜群众 } @Override public void addObserver(GossipObserver observer) { observers.add(observer); System.out.println("👥 " + observer.getClass().getSimpleName() + " 加入了吃瓜群"); } @Override public void removeObserver(GossipObserver observer) { observers.remove(observer); System.out.println("🚶 " + observer.getClass().getSimpleName() + " 退群了"); } @Override public void notifyObservers() { for (GossipObserver observer : observers) { observer.update(celebrityName, scandal); } } } // 5. 测试:娱乐圈大戏上演 public class ObserverPatternDemo { public static void main(String[] args) { System.out.println("========== 娱乐圈观察者模式演示 ==========\n"); // 创建八卦中心(被观察者) CelebrityScandal wang = new CelebrityScandal("王某"); // 创建不同的吃瓜群众(观察者) GossipObserver fan1 = new ExcitedFan("狂热粉丝小张"); GossipObserver fan2 = new ExcitedFan("吃瓜少女小李"); GossipObserver journalist = new CalmJournalist(); GossipObserver路人 = new IndifferentPerson(); // 群众陆续加入吃瓜群 wang.addObserver(fan1); wang.addObserver(fan2); wang.addObserver(journalist); wang.addObserver(路人); System.out.println("\n------- 第一波爆料 -------"); // 第一波爆料 wang.newScandal("深夜与神秘女子同回酒店"); System.out.println("\n------- 粉丝退群后第二波爆料 -------"); // 小张退群了 wang.removeObserver(fan1); // 第二波爆料 wang.newScandal("被拍到在超市偷吃试吃品"); } }

运行结果:

========== 娱乐圈观察者模式演示 ========== 👥 ExcitedFan 加入了吃瓜群 👥 ExcitedFan 加入了吃瓜群 👥 CalmJournalist 加入了吃瓜群 👥 IndifferentPerson 加入了吃瓜群 ------- 第一波爆料 ------- ⚡⚡⚡ 狗仔队拍到:王某 深夜与神秘女子同回酒店! 八卦开始传播... 狂热粉丝小张兴奋地尖叫:OMG!王某竟然深夜与神秘女子同回酒店! → 立刻打开微博准备吃瓜🍉 吃瓜少女小李兴奋地尖叫:OMG!王某竟然深夜与神秘女子同回酒店! → 立刻打开微博准备吃瓜🍉 记者冷静地记录: 【独家爆料】王某被曝深夜与神秘女子同回酒店 → 开始写新闻稿📰 路人甲瞥了一眼: 王某?不认识。关我屁事🙄 → 继续刷抖音 ------- 粉丝退群后第二波爆料 ------- 🚶 ExcitedFan 退群了 ⚡⚡⚡ 狗仔队拍到:王某 被拍到在超市偷吃试吃品! 八卦开始传播... 吃瓜少女小李兴奋地尖叫:OMG!王某竟然被拍到在超市偷吃试吃品! → 立刻打开微博准备吃瓜🍉 记者冷静地记录: 【独家爆料】王某被曝被拍到在超市偷吃试吃品 → 开始写新闻稿📰 路人甲瞥了一眼: 王某?不认识。关我屁事🙄 → 继续刷抖音

三、观察者模式的四要素

// 1️⃣ 主题 (Subject) - "八卦中心" // 负责:管理观察者 + 通知变化 interface Subject { void addObserver(Observer o); void removeObserver(Observer o); void notifyObservers(); } // 2️⃣ 观察者 (Observer) - "吃瓜群众" // 负责:定义反应方式 interface Observer { void update(Object data); } // 3️⃣ 具体主题 (ConcreteSubject) - "具体明星" // 负责:状态变化时触发通知 class ConcreteSubject implements Subject { private List<Observer> observers = new ArrayList<>(); private Object state; // 状态 public void setState(Object newState) { this.state = newState; notifyObservers(); // 状态改变,通知所有人! } } // 4️⃣ 具体观察者 (ConcreteObserver) - "具体粉丝" // 负责:实现具体的反应逻辑 class ConcreteObserver implements Observer { @Override public void update(Object data) { // 对状态变化的反应 } }

四、什么时候用观察者模式?

🎯适用场景(三个字:要通知!)

  1. 事件驱动系统- "有事发生,马上报告!"

    // GUI按钮点击事件 button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("按钮被点了!"); } });
  2. 消息订阅系统- "我有新消息,订阅者请查收"

    // 新闻订阅 newsPublisher.subscribe(user1); newsPublisher.subscribe(user2); // 新文章发布 → 所有订阅者收到推送
  3. 数据监控系统- "数据变了,快更新显示!"

    // 股票价格监控 stock.addObserver(new StockDisplay()); // 显示板 stock.addObserver(new AlertSystem()); // 警报系统 stock.addObserver(new TraderBot()); // 自动交易机器人 // 股价变动 → 所有观察者立即行动
  4. MVC模式- "模型变了,视图快刷新"

    // Model数据变化 model.setData(newData); // → 自动通知所有关联的View更新界面

📦实际项目中的例子

// 电商订单状态通知系统 class Order { private List<OrderObserver> observers = new ArrayList<>(); private String status; public void setStatus(String newStatus) { this.status = newStatus; notifyObservers(); } public void addObserver(OrderObserver observer) { observers.add(observer); } private void notifyObservers() { for (OrderObserver observer : observers) { observer.onOrderStatusChanged(this, status); } } } // 不同的观察者 class CustomerNotifier implements OrderObserver { public void onOrderStatusChanged(Order order, String status) { sendSMS("尊敬的客户,您的订单状态已更新为:" + status); } } class WarehouseSystem implements OrderObserver { public void onOrderStatusChanged(Order order, String status) { if ("已支付".equals(status)) { prepareGoods(order); // 准备发货 } } } class AccountingSystem implements OrderObserver { public void onOrderStatusChanged(Order order, String status) { if ("已完成".equals(status)) { recordRevenue(order); // 记录收入 } } }

五、观察者模式的变体

1.推模型 vs 拉模型

// 推模型:把数据直接推给观察者(常用) void update(String celebrity, String scandal) { // 直接拿到所有信息 } // 拉模型:观察者自己从主题拉取数据 void update(Subject subject) { String scandal = subject.getScandal(); // 自己获取需要的数据 }

2.Java内置支持(已过时但要知道)

import java.util.Observable; // 主题 import java.util.Observer; // 观察者 // 但注意:Observable是类不是接口,Java 9后已废弃

3.事件总线(Event Bus)- 观察者模式的升级版

// 更灵活的事件处理 eventBus.register(subscriber); // 注册订阅者 eventBus.post(new OrderEvent()); // 发布事件 // 所有对OrderEvent感兴趣的订阅者都会收到

六、观察者模式的优缺点

👍优点

  • 松耦合:主题不知道观察者的具体细节,只知道接口
  • 动态添加:运行时可以随时添加/移除观察者
  • 一对多通知:一个变化可以通知多个对象
  • 符合开闭原则:新增观察者无需修改主题

👎缺点

  • 内存泄漏风险:如果观察者没正确移除,可能无法被垃圾回收
  • 通知顺序不确定:观察者被通知的顺序通常无法保证
  • 性能问题:观察者太多时,通知可能变慢
  • 循环依赖:观察者之间相互观察可能导致死循环

🚨注意事项

// 1. 避免在观察者方法中修改主题(可能导致循环或异常) @Override public void update(Subject subject) { // ❌ 错误做法:可能导致递归调用 subject.setState("新状态"); // ✅ 正确做法:只读取不修改 String state = subject.getState(); } // 2. 考虑异步通知(避免阻塞) class AsyncSubject extends Subject { private ExecutorService executor = Executors.newCachedThreadPool(); @Override protected void notifyObservers() { for (Observer observer : observers) { executor.submit(() -> observer.update(data)); // 异步执行 } } }

七、与其他模式的关系

模式关系
发布-订阅模式观察者模式的升级版,通过消息队列解耦
中介者模式都是处理对象间通信,但中介者是集中式管理
责任链模式都是传递事件,但责任链是链式处理

八、生活中的观察者模式

场景主题观察者触发时机
微信群群主群成员有人发消息
天气预报气象局手机APP/电视台天气数据更新
网红直播主播观众开始直播
GitHub仓库代码仓库Star的用户有新提交
电商打折商品收藏的用户价格变化

九、总结:一句话记住

观察者模式 = "我有情况,马上通知大家"

  • 主题:就是那个"有情况的人"
  • 观察者:就是"等着听消息的人"
  • 核心思想解耦+自动通知

📝使用时机判断表

问自己这些问题:

  1. ✅ 一个对象的状态变化需要通知其他对象吗?
  2. ✅ 被通知的对象数量不确定或可能变化吗?
  3. ✅ 不想让这些对象紧密耦合吗?

如果都是"是" → 用观察者模式!

🎯最佳实践

  1. 优先用接口:主题和观察者都用接口定义
  2. 考虑线程安全:多线程环境下要同步
  3. 避免过度使用:简单的回调可能就够了
  4. 使用现有框架:Spring事件、Guava EventBus等

记住口诀:"状态变,发通知;观察者,自动动;松耦合,真轻松!"🎉

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

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

相关文章

Linux如何查看线程?

‌Linux线程‌是指在进程内部的一个执行单元&#xff0c;它是进程内部的控制序列&#xff0c;用于描述进程内部的一个执行流&#xff0c;且共享进程的地址空间和资源&#xff0c;那么Linux如何查看线程?提供了多种方法来查看系统中的线程&#xff0c;以下是最常用的方法。1、使…

PMSG永磁同步发电机并网仿真模型研究:基于SVPWM与叶尖速比法的控制策略与性能分析

PMSG永磁同步发电机并网仿真模型 &#xff08;1&#xff09;主要包括发电机、整流器、逆变器&#xff08;双pwm控制&#xff09;、电网、控制、显示等部分&#xff1b; &#xff08;2&#xff09;风机最大功率跟踪mppt采用最佳叶尖速比法&#xff1b; &#xff08;3&#xff09…

基于PLC的六层电梯控制系统设计

3 基于PLC控制的六层电梯设计总体方案 3.1 电梯的硬件系统组成 在办公楼、小区住宅、大厦等场所&#xff0c;电梯的存在是极为的重要&#xff0c;同时电梯从某些方面也体现出现代的工艺水平。其实电梯的结构就和人体的结构是一样的&#xff0c;它的电器方面就像是人的血管经脉一…

学长亲荐9个AI论文写作软件,助你搞定本科毕业论文!

学长亲荐9个AI论文写作软件&#xff0c;助你搞定本科毕业论文&#xff01; 论文写作的“救星”来了&#xff0c;AI 工具正在改变你的学习方式 对于许多本科生来说&#xff0c;撰写毕业论文是一场漫长而艰难的旅程。从选题、查找资料到撰写初稿、反复修改&#xff0c;每一个环节…

一体化智慧校园平台 助力校园数字化建设

✅作者简介&#xff1a;合肥自友科技 &#x1f4cc;核心产品&#xff1a;智慧校园平台(包括教工管理、学工管理、教务管理、考务管理、后勤管理、德育管理、资产管理、公寓管理、实习管理、就业管理、离校管理、科研平台、档案管理、学生平台等26个子平台) 。公司所有人员均有多…

MySQL大事务的Recovery优化

你有没有碰到过mysqld进程启动了很长时间也起不来的情况&#xff1f;这时候我们可以用perf top命令查看一下MySQL进程主要在干什么事情。如果你查看到的信息如下图所示&#xff0c;启动过程中MySQL的主线程(mysqld_main函数开始的线程)绝大多数的时间都花在了回滚事务上。那么很…

智慧校园一站式解决方案 | 创新教育前沿平台

✅作者简介&#xff1a;合肥自友科技 &#x1f4cc;核心产品&#xff1a;智慧校园平台(包括教工管理、学工管理、教务管理、考务管理、后勤管理、德育管理、资产管理、公寓管理、实习管理、就业管理、离校管理、科研平台、档案管理、学生平台等26个子平台) 。公司所有人员均有多…

智慧校园软件平台:实现校园管理的统一入口与数据融合

✅作者简介&#xff1a;合肥自友科技 &#x1f4cc;核心产品&#xff1a;智慧校园平台(包括教工管理、学工管理、教务管理、考务管理、后勤管理、德育管理、资产管理、公寓管理、实习管理、就业管理、离校管理、科研平台、档案管理、学生平台等26个子平台) 。公司所有人员均有多…

日常渗透测试怎么玩?通杀漏洞挖掘的实现方法看这里

如何在日常渗透中实现通杀漏洞挖掘&#xff1f; 你是不是天天遇到了edu刷屏&#xff1f; 看到了某些漏洞平台&#xff0c;某些人交了一千个公益漏洞&#xff1f; 是不是觉得很牛逼&#xff1f;其实不然&#xff0c;都不难&#xff0c;其实如果我要是想刷这玩意&#xff0c;可…

基于CODESYS开发的多轴运动控制程序框架将逻辑和运动控制分开,通过封装单轴控制功能块来操作...

基于CODESYS开发的多轴运动控制程序框架将逻辑和运动控制分开&#xff0c;通过封装单轴控制功能块来操作该功能块&#xff0c;包括归零、点动、相对定位、绝对定位、设置当前位置、伺服模式切换等功能。程序框架由主程序按照状态调用&#xff0c;包括归零模式、手动模式、自动模…

瀚高数据库中 java代码类型与bit对应

文章目录环境症状问题原因解决方案环境 系统平台&#xff1a;Microsoft Windows (64-bit) 10 版本&#xff1a;4.7.6 症状 问题原因 MySQL中bit类型迁移至瀚高数据库bit类型&#xff0c;然后程序中适配报Booleanbit错误&#xff0c;java类型与数据库对应关系如下 标准SQL数…

可靠性测试

我们认为软件可靠性始终是重要的&#xff0c;但它对于任务关键型、安全关键型和高使用率系统是必不可少的。如您所料&#xff0c;可靠性测试可用于降低可靠性问题的风险。可靠性故障背后的常见问题包括内存泄漏、磁盘碎片和耗尽、间歇性基础设施问题以及超时值低于可行值。 可…

用Spring的ApplicationEventPublisher进行事件发布和监听

概述 有时候&#xff0c;我们只是想发布一些本地的事件&#xff0c;并不需要引入MQ的&#xff0c;可以直接使用Spring的ApplicationEventPublisher来完成简单事件的发布和监听的。 比如像下面的场景&#xff0c;ApplicationEventPublisher就够用了。 模块间的逻辑解耦&#…

nacos服务安装并启动

nacos服务安装并启动1、介绍2、下载nacos3、下载jdk4、修改配置文件5、修改启动程序文件6、启动nacos服务1、介绍 Nacos是一款集服务发现、配置管理与服务管理于一体的云原生平台&#xff0c;旨在帮助开发者更敏捷地构建和管理微服务架构。 2、下载nacos 下载地址&#xff1…

方法类的倒推过程结束 七

完全同意,而且这是让“方法体系”不发散的关键约束:方法里的所有东西都只能引用你世界树里已经存在的节点类型与载体,不允许发明一套“方法专用数据结构宇宙”。 下面我把“条件是什么、动作是什么、结果是什么”用你现有的对象(存在/场景/特征类型/特征值节点等)重新落一…

PaperNex领衔9款AI论文工具实操指南:半天3万字+真实参考文献

前言&#xff1a;为什么你需要这篇AI论文工具实操指南 面对毕业论文、课题申报、期刊投稿&#xff0c;大学生、研究生、科研人员常陷入时间紧、资料杂、写作难的三重困境。AI写作工具的出现&#xff0c;正在把“写作门槛”降到地板级——但要挑对工具、用对方法&#xff0c;才…

人工智能之数字生命-场景类的功能

场景是世界树的“空间承载体”。存在和特征像贴在场景上的标签,而场景本身负责把空间织成一张可走、可查、可拼接的地图。 我按你这段描述,把“场景类应该关心的三类关系”梳理成一个很稳定的结构:内关系、横关系、上关系。对应世界树里也自然形成“场景占多数层”的形态。…

50个域渗透手法全覆盖 万字长文 适合收藏!从零基础入门到精通,收藏这一篇就够了!

50个域渗透手法全覆盖 万字长文 适合收藏&#xff01; 在大型企业网络攻防演练与真实攻防对抗中&#xff0c;攻击者一旦突破边界进入内网&#xff0c;Active Directory (AD) 域环境便成为核心目标。掌握域渗透的完整路径和多样化手法&#xff0c;既是攻击方扩大战果的关键&…

收藏必备!情境工程:大模型时代企业知识管理系统的革命性变革

文章探讨了情境工程如何重塑企业知识管理系统&#xff0c;从传统"文档存储检索"模式转变为"主动赋能"。通过场景感知、动态连接和人机协同进化&#xff0c;构建企业"智能认知中枢"&#xff0c;实现决策质量跃升、组织能力沉淀和创新加速。系统五…

一文搞懂大模型智能体工作原理:从PEAS模型到TAO循环,小白也能轻松入门!

本文拆解了大模型智能体(Agent)的工作原理&#xff0c;通过PEAS模型介绍智能体的四要素(性能指标、环境、执行器、传感器)&#xff0c;分析其面对的不完整、不稳定等环境特点&#xff0c;详细解释了"感知→思考→行动→再次感知"的循环过程&#xff0c;以及Thought-A…