当前位置: 首页 > news >正文

【设计模式】【行为型模式】观察者模式(Observer)

👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD
🔥 2025本人正在沉淀中… 博客更新速度++
📫 欢迎+V: flzjcsg2,我们共同讨论Java深渊的奥秘
🎵 当你的天空突然下了大雨,那是我在为你炸乌云

文章目录

  • 一、入门
    • 什么是观察者模式?
    • 为什么要观察者模式?
    • 怎么实现观察者模式?
  • 二、观察者模式在源码中运用
    • Java 中的 java.util.Observer 和 java.util.Observable
      • Observer和Observable的使用
      • Observer和Observable的源码实现
    • Spring 框架中的事件机制
      • Spring事件机制的使用
      • Spring的事件机质的源码实现
  • 三、总结
    • 观察者模式的优点
    • 观察者模式的缺点
    • 观察者模式的适用场景
  • 参考

一、入门

什么是观察者模式?

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

为什么要观察者模式?

假设我们正在开发一个天气预报系统,其中:

  • WeatherStation(气象站):负责收集天气数据(如温度、湿度等)。
  • Display(显示设备):负责显示天气数据,比如手机App、电子屏等。

当气象站的数据更新时,所有显示设备都需要实时更新显示内容。
下面是没有观察者模式时的实现:

class WeatherStation {private float temperature;private float humidity;private PhoneDisplay phoneDisplay;private TVDisplay tvDisplay;public void setPhoneDisplay(PhoneDisplay phoneDisplay) {this.phoneDisplay = phoneDisplay;}public void setTVDisplay(TVDisplay tvDisplay) {this.tvDisplay = tvDisplay;}public void removePhoneDisplay() {phoneDisplay = null;}public void removeTVDisplay() {phoneDisplay = null;}public void setMeasurements(float temperature, float humidity) {this.temperature = temperature;this.humidity = humidity;// 手动调用显示设备的更新方法if (phoneDisplay != null) {phoneDisplay.update(temperature, humidity);}if (tvDisplay != null) {tvDisplay.update(temperature, humidity);}}
}

紧耦合
如果没有观察者模式,气象站需要直接知道所有显示设备的存在,并手动调用它们的更新方法。例如:
问题:

  • 气象站和显示设备之间是紧耦合的,气象站需要知道所有显示设备的具体实现。
  • 如果新增一个显示设备(比如智能手表),需要修改气象站的代码,违反了开闭原则(对扩展开放,对修改关闭)。

难以动态管理依赖
如果显示设备需要动态添加或移除(比如用户关闭了某个显示设备),气象站需要手动管理这些设备的引用。

扩展性差
如果未来需要支持更多类型的观察者(比如日志记录器、报警系统等),气象站的代码会变得越来越臃肿,难以维护。

怎么实现观察者模式?

在观察者模式中有如下角色:

  • Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
  • ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
  • Observer:抽象观察者,是观察者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
  • ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。

【案例】天气站 - 改
在这里插入图片描述
Observer观察者: Observer接口

interface Observer {void update(float temperature, float humidity);
}

Subject主题: subject接口

interface Subject {void registerObserver(Observer observer);void removeObserver(Observer observer);void notifyObservers();
}

实现具体主题(气象站): WeatherStation

class WeatherStation implements Subject {private List<Observer> observers = new ArrayList<>();private float temperature;private float humidity;@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(temperature, humidity);}}public void setMeasurements(float temperature, float humidity) {this.temperature = temperature;this.humidity = humidity;notifyObservers(); // 通知所有观察者}
}

实现具体观察者(显示设备): PhoneDisplay类和TVDisplay

class PhoneDisplay implements Observer {@Overridepublic void update(float temperature, float humidity) {System.out.println("手机显示:温度 = " + temperature + ",湿度 = " + humidity);}
}class TVDisplay implements Observer {@Overridepublic void update(float temperature, float humidity) {System.out.println("电视显示:温度 = " + temperature + ",湿度 = " + humidity);}
}

测试类

public class WeatherApp {public static void main(String[] args) {WeatherStation weatherStation = new WeatherStation();Observer phoneDisplay = new PhoneDisplay();Observer tvDisplay = new TVDisplay();weatherStation.registerObserver(phoneDisplay);weatherStation.registerObserver(tvDisplay);// 更新天气数据weatherStation.setMeasurements(25.5f, 60.0f);// 移除一个观察者weatherStation.removeObserver(tvDisplay);// 再次更新天气数据weatherStation.setMeasurements(26.0f, 58.0f);}
}

运行结果

手机显示:温度 = 25.5,湿度 = 60.0
电视显示:温度 = 25.5,湿度 = 60.0
手机显示:温度 = 26.0,湿度 = 58.0

二、观察者模式在源码中运用

Java 中的 java.util.Observer 和 java.util.Observable

Java 标准库中提供了观察者模式的实现,分别是 Observer 接口和 Observable 类。

  • Observable 是被观察者的基类,内部维护了一个观察者列表,并提供了 addObserver、deleteObserver 和 notifyObservers 方法。
  • Observer 是观察者接口,定义了 update 方法,用于接收通知。

Observer和Observable的使用

被观察者(具体主题):WeatherData

// 被观察者(主题)
class WeatherData extends Observable {private float temperature;private float humidity;public void setMeasurements(float temperature, float humidity) {this.temperature = temperature;this.humidity = humidity;setChanged(); // 标记状态已改变notifyObservers(); // 通知观察者}public float getTemperature() {return temperature;}public float getHumidity() {return humidity;}
}

观察者(具体观察者): Display

// 观察者
class Display implements Observer {@Overridepublic void update(Observable o, Object arg) {if (o instanceof WeatherData) {WeatherData weatherData = (WeatherData) o;float temperature = weatherData.getTemperature();float humidity = weatherData.getHumidity();System.out.println("当前温度: " + temperature + ",湿度: " + humidity);}}
}

测试

public class ObserverPatternDemo {public static void main(String[] args) {WeatherData weatherData = new WeatherData();Display display = new Display();weatherData.addObserver(display); // 注册观察者weatherData.setMeasurements(25.5f, 60.0f); // 更新数据并通知观察者}
}

输出结果

当前温度: 25.5,湿度: 60.0

Observer和Observable的源码实现

观察者:Observer类,入参Observable o:被观察的对象(主题)和 Object arg:传递给观察者的额外参数(可选)。

public interface Observer {void update(Observable o, Object arg);
}

主题Observable类。
我们可以看到Vector<Observer>存储观察者列表。并且因为加了synchronized关键字,这些方法都是线程安全的。notifyObservers方法会遍历观察者列表,并调用每个观察者的update方法。

public class Observable {// 标记对象是否已改变private boolean changed = false;// 观察者列表(使用 Vector 保证线程安全)private Vector<Observer> obs;public Observable() {obs = new Vector<>();}// 添加观察者public synchronized void addObserver(Observer o) {if (o == null)throw new NullPointerException();if (!obs.contains(o)) {obs.addElement(o);}}// 删除观察者public synchronized void deleteObserver(Observer o) {obs.removeElement(o);}// 通知所有观察者(无参数)public void notifyObservers() {notifyObservers(null);}// 通知所有观察者(带参数)public void notifyObservers(Object arg) {Observer[] arrLocal;// 同步块,确保线程安全synchronized (this) {if (!changed) // 如果没有变化,直接返回return;arrLocal = obs.toArray(new Observer[obs.size()]);clearChanged(); // 重置变化标志}// 遍历观察者列表,调用 update 方法for (Observer observer : arrLocal) {observer.update(this, arg);}}// 删除所有观察者public synchronized void deleteObservers() {obs.removeAllElements();}// 标记对象已改变protected synchronized void setChanged() {changed = true;}// 重置变化标志protected synchronized void clearChanged() {changed = false;}// 检查对象是否已改变public synchronized boolean hasChanged() {return changed;}// 返回观察者数量public synchronized int countObservers() {return obs.size();}
}

Spring 框架中的事件机制

Spring 框架中的事件机制是基于观察者模式实现的。它允许开发者定义自定义事件,并通过监听器(观察者)来处理这些事件。

Spring事件机制的使用

自定义事件

class CustomEvent extends ApplicationEvent {private String message;public CustomEvent(Object source, String message) {super(source);this.message = message;}public String getMessage() {return message;}
}

事件监听器(观察者)

@Component
class CustomEventListener implements ApplicationListener<CustomEvent> {@Overridepublic void onApplicationEvent(CustomEvent event) {System.out.println("收到事件: " + event.getMessage());}
}

事件发布者

@Component
class CustomEventPublisher {private final AnnotationConfigApplicationContext context;public CustomEventPublisher(AnnotationConfigApplicationContext context) {this.context = context;}public void publishEvent(String message) {context.publishEvent(new CustomEvent(this, message));}
}

配置类

@Configuration
@ComponentScan
class AppConfig {}

测试类

public class SpringEventDemo {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);CustomEventPublisher publisher = context.getBean(CustomEventPublisher.class);publisher.publishEvent("Hello, Spring Event!");context.close();}
}

输出内容

收到事件: Hello, Spring Event!

Spring的事件机质的源码实现

Spring 事件机制的核心组件包括:

  • ApplicationEvent:事件的基类,所有自定义事件都需要继承它。对应观察者模式中的“事件”。
  • ApplicationListener:观察者接口,定义了处理事件的方法。对应观察者模式中的“观察者”。
  • ApplicationEventPublisher:事件发布者接口,用于发布事件。对应观察者模式中的“主题”。
  • ApplicationEventMulticaster:事件广播器,负责将事件分发给所有监听器。类似于观察者模式中的“通知机制”。

ApplicationEventApplicationEvent 是所有事件的基类,它继承自 java.util.EventObject

public abstract class ApplicationEvent extends EventObject {private final long timestamp;            // timestamp: 事件发生的时间戳。public ApplicationEvent(Object source) { // source:事件源,通常是发布事件的对象。super(source);this.timestamp = System.currentTimeMillis();}public final long getTimestamp() {return this.timestamp;}
}

ApplicationListener接口: ApplicationListener是观察者接口,定义了处理事件的方法。

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {void onApplicationEvent(E event);  // 当事件发生时,会调用此方法。
}

ApplicationEventPublisher接口: 是事件发布者接口,用于发布事件。

@FunctionalInterface
public interface ApplicationEventPublisher {default void publishEvent(ApplicationEvent event) {publishEvent((Object) event);}void publishEvent(Object event);
}

ApplicationEventMulticaster接口:是事件广播器接口,负责将事件分发给所有监听器。

public interface ApplicationEventMulticaster {void addApplicationListener(ApplicationListener<?> listener);void addApplicationListenerBean(String listenerBeanName);void removeApplicationListener(ApplicationListener<?> listener);void removeApplicationListenerBean(String listenerBeanName);void removeAllListeners();void multicastEvent(ApplicationEvent event); void multicastEvent(ApplicationEvent event, ResolvableType eventType);
}

SimpleApplicationEventMulticasterSimpleApplicationEventMulticasterApplicationEventMulticaster的默认实现类。

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {// 遍历所有监听器,并调用 onApplicationEvent 方法。@Overridepublic void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {Executor executor = getTaskExecutor();if (executor != null) {executor.execute(() -> invokeListener(listener, event));} else {invokeListener(listener, event);}}}// 实际调用监听器的 onApplicationEvent 方法。protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {try {listener.onApplicationEvent(event);} catch (ClassCastException ex) {// 处理类型转换异常}}
}

三、总结

观察者模式的优点

解耦:主题(Subject)和观察者(Observer)之间是松耦合的(主题不需要知道观察者的具体实现,只需要知道观察者接口,观察者也不需要知道主题的具体实现,只需要实现观察者接口)
动态管理依赖:观察者可以动态注册和注销,而不需要修改主题的代码。支持运行时动态添加或移除观察者,灵活性高。
符合开闭原则:可以轻松添加新的观察者,而不需要修改主题的代码。主题的代码不需要因为观察者的变化而修改。
广播通信:主题可以一次性通知所有观察者,适合一对多的通信场景。观察者可以根据需要选择是否响应通知。
职责分离:主题负责维护状态和通知观察者。观察者负责处理状态变化的逻辑。职责分离使得代码更加清晰和可维护。

观察者模式的缺点

  • 性能问题
    • 如果观察者数量非常多,通知所有观察者可能会消耗大量时间。
    • 如果观察者的处理逻辑复杂,可能会导致性能瓶颈。
  • 内存泄漏
    • 如果观察者没有正确注销,可能会导致观察者无法被垃圾回收,从而引发内存泄漏。
    • 特别是在长时间运行的应用中,需要特别注意观察者的生命周期管理。
  • 调试困难
    • 由于观察者和主题是松耦合的,调试时可能难以追踪事件的传递路径。
    • 如果观察者的处理逻辑出现问题,可能不容易定位问题根源。
  • 事件顺序不确定
    • 观察者收到通知的顺序通常是不确定的,如果业务逻辑对顺序有要求,可能需要额外的处理。

观察者模式的适用场景

  • 事件驱动系统
    • 当一个对象的状态变化需要触发其他对象的操作时,可以使用观察者模式。
    • 例如:GUI 框架中的按钮点击事件、Spring 框架中的事件机制。
  • 一对多的依赖关系
    • 当一个对象的状态变化需要通知多个其他对象时,可以使用观察者模式。
    • 例如:气象站和多个显示设备的关系。
  • 跨系统的消息通知
    • 在分布式系统中,观察者模式可以用于实现消息的发布和订阅。
    • 例如:消息队列(MQ)中的发布-订阅模型。
  • 状态变化的广播
    • 当一个对象的状态变化需要广播给多个对象时,可以使用观察者模式。
    • 例如:游戏中的角色状态变化通知其他系统(如 UI、音效等)。
  • 解耦业务逻辑
    • 当需要将业务逻辑解耦为多个独立的模块时,可以使用观察者模式。
    • 例如:订单系统中的订单状态变化通知库存系统、物流系统等。

参考

黑马程序员Java设计模式详解, 23种Java设计模式(图解+框架源码分析+实战)_哔哩哔哩_bilibili

相关文章:

【设计模式】【行为型模式】观察者模式(Observer)

&#x1f44b;hi&#xff0c;我不是一名外包公司的员工&#xff0c;也不会偷吃茶水间的零食&#xff0c;我的梦想是能写高端CRUD &#x1f525; 2025本人正在沉淀中… 博客更新速度 &#x1f4eb; 欢迎V&#xff1a; flzjcsg2&#xff0c;我们共同讨论Java深渊的奥秘 &#x1f…...

机器学习: 逻辑回归

概念与定义 逻辑回归是一种用于分类问题的统计方法。它通过计算目标变量的概率来预测类别归属,并假设数据服从伯努利分布(二分类)或多项式分布(多分类)。逻辑回归模型输出的是概率值,通常使用sigmoid函数将线性组合映射到0和1之间。 1. 概念 逻辑回归用于解决分类问题…...

域名解析—互联网世界的导航系统

在互联网的世界里&#xff0c;每个网站都像一座“城市”&#xff0c;而用户要找到这些“城市”&#xff0c;必须依赖一套精准的导航系统——这就是域名解析。无论是浏览网页、发送邮件&#xff0c;还是使用移动应用&#xff0c;域名解析都在背后默默支撑着用户的每一次访问。本…...

PAT乙级真题 — 1080 MOOC期终成绩(java)【测试点3超时】

对于在中国大学MOOC&#xff08;http://www.icourse163.org/ &#xff09;学习“数据结构”课程的学生&#xff0c;想要获得一张合格证书&#xff0c;必须首先获得不少于200分的在线编程作业分&#xff0c;然后总评获得不少于60分&#xff08;满分100&#xff09;。总评成绩的计…...

【Prometheus】如何通过prometheus监控redis实时运行状态,并实现告警通知

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…...

ARM Cortex-M3/M4 权威指南 笔记【一】技术综述

一、Cortex-M3/M4 处理器的一般信息 1.1 处理器类型 ARM Cortex-M 为 32 位 RISC&#xff08;精简指令集&#xff09;处理器&#xff0c;其具有&#xff1a; 32位寄存器32位内部数据通路32位总线接口 除了 32 位数据&#xff0c;Cortex-M 处理器&#xff08;以及其他任何 A…...

【Qt】定期清理程序

在现有Qt程序中实现可配置日志保存天数的代码示例&#xff0c;分为界面修改、配置存储和核心逻辑三部分&#xff1a; // 1. 在配置文件&#xff08;如settings.h&#xff09;中添加保存天数的配置项 class Settings { public:int logRetentionDays() const {return m_settings…...

基于51单片机的门禁刷卡器proteus仿真

地址&#xff1a;https://pan.baidu.com/s/1j0KAmH5pVGWZWRpT6p5hBg 提取码&#xff1a;1234 仿真图&#xff1a; 芯片/模块的特点&#xff1a; AT89C52/AT89C51简介&#xff1a; AT89C52/AT89C51是一款经典的8位单片机&#xff0c;是意法半导体&#xff08;STMicroelectron…...

二、数据持久化篇(深度增强版)

二、数据持久化篇&#xff08;深度增强版&#xff09; 2.1 JDBC Template深度解析 架构设计思想 #mermaid-svg-y2IrKiVu2gzenoCB {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-y2IrKiVu2gzenoCB .error-icon{fil…...

时间敏感和非时间敏感流量的性能保证配置

论文标题 中文标题&#xff1a; 时间敏感和非时间敏感流量的性能保证配置 英文标题&#xff1a; Provisioning of Time-Sensitive and non-Time-Sensitive Flows with Assured Performance 作者信息 Luis Velasco, Gianluca Graziadei, Sima Barzegar, Marc Ruiz Optical Co…...

k8s管理工具之lens

什么是lens Lens 是当前市场上最强大的K8S IDE。它是一个独立的单机应用&#xff0c;可以同时运行在macOS、Windows和Linux上。 作为K8S IDE&#xff0c;该有的它基本都有了&#xff01; 集群管理 导入已有集群 首先&#xff0c;你需要在 Lens 中添加你的 Kubernetes 集群。点…...

kafka介绍,kafka集群环境搭建,kafka命令测试,C++实现kafka客户端

目录 kafka介绍kafka集群环境搭建zookeeper安装与配置kafka安装与配置 kafka命令测试C实现kafka客户端librdkafka库编译新版本cmake编译cppkafka库编译C实现kafka生产者和消费者客户端 kafka介绍 定义与概述 Apache Kafka 是一个开源的分布式流处理平台&#xff0c;最初由 Lin…...

DeepSeek的蒸馏技术:让模型推理更快

DeepSeek系列模型&#xff0c;如DeepSeek-R1-Distill-Qwen-7B&#xff0c;采用了知识蒸馏&#xff08;Knowledge Distillation&#xff09;技术&#xff0c;这是一种强大的模型压缩和优化方法。通过蒸馏&#xff0c;DeepSeek模型在保持甚至提升性能的同时&#xff0c;实现了更快…...

SAP-ABAP:dialog界面中的数据块Event Block详解举例

在SAP的Dialog程序开发中&#xff0c;Event Block&#xff08;事件块&#xff09;是屏幕流逻辑&#xff08;Flow Logic&#xff09;中的关键部分&#xff0c;用于定义屏幕在特定事件触发时执行的逻辑。Event Block通常与ABAP模块&#xff08;Module&#xff09;结合使用&#x…...

微信小程序 - 模版语法

声明和绑定数据 小程序页面中使用的数据均需要在 Page() 方法的 data 对象中进行声明定义 在将数据声明好以后&#xff0c;需要在 WXML 中绑定数据&#xff0c;数据绑定最简单的方式是使用 Mustache 语法&#xff08;双大括号&#xff09;将变量包起来。 在 {{ }} 内部可以做…...

mapbox进阶,添加绘图扩展插件,裁剪线

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️MapboxDraw 绘图控件二、🍀添加绘图扩…...

Dav_笔记14:优化程序提示 HINTs -2

优化方法和目标的提示 ALL_ROWS和FIRST_ROWS&#xff08;n&#xff09;提示允许您在优化方法和目标之间进行选择。如果SQL语句具有指定优化方法和目标的提示&#xff0c;则优化程序将使用指定的方法&#xff0c;无论是否存在统计信息&#xff0c;OPTIMIZER_MODE初始化参数的值…...

Oracle ORA-00054

ORA-00054: resource busy and acquire with NOWAlT specified or timeout expire 错误 ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired 是 Oracle 数据库中常见的一个错误&#xff0c;通常发生在尝试获取一个已经被其他会话占用的资源时。这…...

ABB能源自动化选用宏集Cogent DataHub避免DCOM问题,实现高效、安全的数据传输

案例概况 ABB能源自动化公司通过宏集Cogent DataHub软件将电厂设施的数据实时传输到公司办公室&#xff0c;实现了OPC隧道/镜像解决方案&#xff0c;在电厂和公司网络之间建立了一个安全、可靠的连接&#xff0c;确保数据传输的高度安全&#xff0c;减少入侵风险。 &#xff0…...

IP地址有哪些类型?

IP地址是计算机网络中用来识别和查找设备的唯一标识符。根据其作用和使用范围&#xff0c;IP地址可分为以下几种类型&#xff1a; 1.局域网IP地址 局域网IP地址又称内网IP地址&#xff0c;是局域网内用来识别和查找局域网设备的地址。局域网是一个相对较小的网络&#xff0c;…...

网络安全评估:保障设备与系统安全的关键

保障网络安全离不开对入网设备的安全评估&#xff0c;这种评估运用了多种技术和手段&#xff0c;对网络中的设备与系统进行详尽的检查。它能迅速发现并排除潜在的安全风险&#xff0c;对网络系统的安全稳定运行具有极其关键的作用。 测评目的 确保网络系统的安全与稳定是网络…...

一竞技瓦拉几亚S4预选:YB 2-0击败GG

在2月11号进行的PGL瓦拉几亚S4西欧区预选赛上,留在欧洲训练的YB战队以2-0击败GG战队晋级下一轮。双方对阵第二局:对线期YB就打出了优势,中期依靠卡尔带队进攻不断扩大经济优势,最终轻松碾压拿下比赛胜利,以下是对决战报。 YB战队在天辉。阵容是潮汐、卡尔、沙王、隐刺、发条。G…...

管式超滤膜分离技术在茶澄清浓缩领域的创新应用

管式超滤膜分离技术在茶澄清浓缩领域展现出广阔的前景&#xff0c;其独特优势和应用效果正逐渐改变着茶饮料行业的生产方式。以下是几个关键点&#xff0c;说明了这一技术为何具有如此积极的发展潜力&#xff1a; 1. 高效澄清与保留风味 管式超滤膜具有高精度的过滤能力&#x…...

maven web项目如何定义filter

在 Maven Web 项目中定义一个 Servlet 过滤器&#xff08;Filter&#xff09;&#xff0c;需要遵循 Java Servlet 规范&#xff0c;并利用 Maven 来管理项目结构和依赖。下面是如何在 Maven Web 项目中定义和配置一个过滤器的基本步骤&#xff1a; 1. 创建过滤器类 首先&…...

如何在MacOS上查看edge/chrome的扩展源码

步骤 进入管理扩展页面点击详细信息复制对应id在命令行键入 open ~/Library/Application Support/Microsoft Edge/Default/Extensions/${你刚刚复制的id} 即可打开访达中对应的更目录 注意 由于原生命令行无法直接处理空格 ,所以需要加转义符\,即&#xff1a;open ~/Librar…...

【学术投稿-2025年计算机视觉研究进展与应用国际学术会议 (ACVRA 2025)】CSS样式解析:行内、内部与外部样式的区别与优先级分析

简介 2025年计算机视觉研究进展与应用&#xff08;ACVRA 2025&#xff09;将于2025年2月28-3月2日在中国广州召开&#xff0c;会议将汇聚世界各地的顶尖学者、研究人员和行业专家&#xff0c;聚焦计算机视觉领域的最新研究动态与应用成就。本次会议将探讨前沿技术&#xff0c;…...

redis记录用户在线状态+活跃度

1.记录用户在线状态 redis的Bitmap记录用户在线状态 使用一个大的Bitmap,每个bit位对应一个用户IDbit值1表示在线,0表示离线用户ID与bit位的映射关系: bit位置 用户ID % bitmap容量 具体实现: # 用户上线时,设置对应bit为1 SETBIT online_users {user_id} 1# 用户下线时,设…...

vmware安装win7

1、版本说明 vmware workstation 16 win7 X64 2、安装步骤 安装步骤有点独特&#xff0c;先配置虚拟机&#xff0c;然后再虚拟机的虚拟光驱里添加下载的win7。 配置完了之后&#xff0c;点击要运行的虚拟机&#xff0c;然后一直往下走就可以完成系统的安装。 3、配置系统以解…...

OpenAI推出的Computer Use智能体:Operator是什么

OpenAI推出的Computer Use智能体:Operator是什么 是一款能像人一样与图形用户界面交互来操作计算机的AI智能体。以下是其核心原理及举例说明: 核心原理 感知: 屏幕截图获取:利用高性能屏幕捕获模块,如基于WebRTC的截图技术,以极低延迟获取高清晰度页面图像,为后续分析…...

[FastAdmin] 上传图片并加水印,压缩图片

1.app\common\library\Upload.php 文件 upload方法 /*** 普通上传* return \app\common\model\attachment|\think\Model* throws UploadException*/public function upload($savekey null){if (empty($this->file)) {throw new UploadException(__(No file upload or serv…...

二、k8s项目的生命周期

项目的生命周期 创建-----------》发布-----------》更新--------》回滚----------》删除 kubectl create deployment nginx1 --imagenginx:1.22 --replicas3 基于deployment控制器创建pod 控制器的名称是nginx1 pod使用的镜像:nginx:1.22 --replicas3 pod的数量有多少 3个…...

MySQL数据库入门到大蛇尚硅谷宋红康老师笔记 基础篇 part 10

第10章_创建和管理表 DDL&#xff1a;数据定义语言。CREATE \ALTER\ DROP \RENAME TRUNCATE DML&#xff1a;数据操作语言。INSERT \DELETE \UPDATE \SELECT&#xff08;重中之重&#xff09; DCL&#xff1a;数据控制语言。COMMIT \…...

python自动化测试之Pytest框架之YAML详解以及Parametrize数据驱动!

一、YAML详解 YAML是一种数据类型&#xff0c;它能够和JSON数据相互转化&#xff0c;它本身也是有很多数据类型可以满足我们接口 的参数类型&#xff0c;扩展名可以是.yml或.yaml 作用&#xff1a; 1.全局配置文件 基础路径&#xff0c;数据库信息&#xff0c;账号信息&…...

deepseek的CoT优势、两阶段训练的有效性学习笔记

文章目录 1 DeepSeek的CoT思维链的优势1.2 open-r1的CoT训练数据1.3 ReAct任务与CoT任务适用场景 2 AI推理方向&#xff1a;deepseek与deepmind的两条路线的差异2.1 PRM与ORM的两大学派分支的差异2.2 DeepSeek-R1的两阶段训练概述 1 DeepSeek的CoT思维链的优势 DeepSeek跟之前…...

计算机网络-MPLS转发原理

在上一篇关于 MPLS 基础的文章中&#xff0c;我们了解了 MPLS 的基本概念、术语以及它在网络中的重要性。今天&#xff0c;我们将深入探讨 MPLS 转发的原理与流程&#xff0c;帮助大家更好地理解 MPLS 是如何在实际网络中工作的。 一、MPLS 转发概述 MPLS 转发的本质是将数据…...

本地部署DeepSeek R1并搭建Web UI实现可视化交互的笔记

经过多天的挣扎和卸载了一些软件&#xff0c;终于下定决心在本地部署DeepSeek R1模型。部署和搭建过程非常简单和方便。 一、下载Ollama 进入Ollama官方网站(https://ollama.com),进入下载下载Ollama页面&#xff08;https://ollama.com/download&#xff09; 根据电脑的操作…...

港中文腾讯提出可穿戴3D资产生成方法BAG,可自动生成服装和配饰等3D资产如,并适应特定的人体模型。

今天给大家介绍一种名为BAG&#xff08;Body-Aligned 3D Wearable Asset Generation&#xff09;的新方法&#xff0c;可以自动生成可穿戴的3D资产&#xff0c;如服装和配饰&#xff0c;以适应特定的人体模型。BAG方法通过构建一个多视图图像扩散模型&#xff0c;生成与人体对齐…...

JUC并发—1.Java集合包底层源码剖析

大纲 1.为什么要对JDK源码剖析 2.ArrayList源码一&#xff1a;基本原理以及优缺点 3.ArrayList源码二&#xff1a;核心方法的原理 4.ArrayList源码三&#xff1a;数组扩容以及元素拷贝 5.LinkedList源码一&#xff1a;优缺点和使用场景 6.LinkedList源码二&#xff1a;双…...

使用Java爬虫获取京东商品评论API接口(JD.item_review)数据

一、引言 在电商领域&#xff0c;商品评论是用户决策的重要参考依据&#xff0c;也是商家优化产品和服务的重要数据来源。京东作为国内领先的电商平台&#xff0c;提供了丰富的API接口供开发者使用&#xff0c;其中JD.item_review接口可以获取商品的评论数据。通过这些数据&am…...

问卷数据分析|SPSS实操之单因素方差分析

适用条件&#xff1a; 检验分类变量和定量变量之间的差异 分类变量数量要大于等于三 具体操作&#xff1a; 1.选择分析--比较平均值--单因素ANOVA检验 2. 下方填分类变量&#xff0c;上方为各个量表数据Z1-Y2 3. 点击选项&#xff0c;选择描述和方差齐性检验 4.此处为结果数…...

【自然语言处理】TextRank 算法提取关键词、短语、句(Python源码实现)

文章目录 一、TextRank 算法提取关键词 [工具包]二、TextRank 算法提取关键短语[工具包]三、TextRank 算法提取关键句[工具包]四、TextRank 算法提取关键句&#xff08;Python源码实现&#xff09; 一、TextRank 算法提取关键词 [工具包] 见链接 【自然语言处理】TextRank 算法…...

Git的常用命令及常见问题处理方法

目录 一、介绍二、常用 Git 命令1. 配置用户信息2. 初始化仓库3. 克隆远程仓库4. 查看状态5. 添加文件到暂存区6. 提交更改7. 查看提交历史8. 查看文件差异9. 查看分支10. 切换分支11. 合并分支12. 处理冲突13. 远程操作14. 标签管理15. 撤销操作 三、常见问题处理方法1. 无法推…...

第6章 6.1 ASP.NET Core MVC 项目

6.1.1 ASP.NET Core MVC 项目的搭建 进入VS环境&#xff0c;创建新的项目&#xff0c;选择【ASP.Net Core Web 应用&#xff08;模型-视图-控制器&#xff09;】如下图所示 编写项目名称 点击创建&#xff0c;进入项目后结构如下所示 wwwroot 文件夹为图片、JS、CSS等静态文件…...

ios通过xib创建控件

之前写过ios动态创建控件及添加事件&#xff0c;纯手工代码写控件&#xff0c;虽然比较灵活&#xff0c;但是就是代码量比较多。这次我们通过xib来创建app下载列表项 AppView.xib。一个imageview,一个label,一个button构成 1.创建AppView.xib 2.再创建xib对应的mode&#xff0…...

缓存组件<keep-alive>

缓存组件<keep-alive> 1.组件作用 组件, 默认会缓存内部的所有组件实例&#xff0c;当组件需要缓存时首先考虑使用此组件。 2.使用场景 场景1&#xff1a;tab切换时&#xff0c;对应的组件保持原状态&#xff0c;使用keep-alive组件 使用&#xff1a;KeepAlive | Vu…...

SAP ABAP调用DeepSeek API大模型接口

搜索了一下DeepSeek&#xff0c;发现有人已经实现了SAP的对接&#xff0c; 不登录网页&#xff0c;SAP如何使用DeepSeek快速编程&#xff0c;ABAP起飞啦~ 按照对应的注册流程和方法。总算做出了第一个能够直连DeepSeek的API abap程序。 效果不错。 report ZTOOL_ABAP_CALL_D…...

大数据与大模型:数字时代的共生力量

引言&#xff1a;大数据与大模型的崭新时代 在数字化浪潮汹涌澎湃的当下&#xff0c;大数据与大模型无疑是最为耀眼的两颗明星 &#xff0c;深刻地改变着我们的生活、工作和思维方式。大数据&#xff0c;作为信息时代的宝藏&#xff0c;蕴含着无尽的价值。从电商平台的海量交易…...

服务器使用宝塔面板Docker应用快速部署 DeepSeek-R1模型,实现Open WebUI访问使用

Deepseek这段时间非常火&#xff0c;最新推理模型Deepseek R1&#xff0c;都想装上试一试&#xff0c;特别是部署到服务器教程网上一堆教程好像没几个部署成功靠谱的&#xff0c;先说服务器上下载Ollama就难倒一堆人&#xff0c;每次都超时。今天终于在宝塔看到一篇 应用安装文…...

Qt - 地图相关 —— 3、Qt调用高德在线地图功能示例(附源码)

效果 作者其他相关文章链接:           Qt - 地图相关 —— 1、加载百度在线地图(附源码)           Qt - 地图相关 —— 2、Qt调用百度在线地图功能示例全集,包含线路规划、地铁线路查询等(附源码)           Qt - 地图相关 —— 3、Qt调用…...

Idea集成deepseek生成代码

今天我带大家在idea上安装CodeGpt插件&#xff0c;这个插件可以根据我们的提示词生产代码&#xff0c;我们一起试试。 1、安装插件 打开idea&#xff0c;再点击setting菜单&#xff0c;按以下步骤操作。 安装完成后&#xff0c;一定要点击第四步“ok”。再次点击菜单setting…...