hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD
2025本人正在沉淀中… 博客更新速度++
欢迎点赞、收藏、关注,跟上我的更新节奏
当你的天空突然下了大雨,那是我在为你炸乌云
文章目录
- 一、入门
- 什么是观察者模式?
- 为什么要观察者模式?
- 怎么实现观察者模式?
- 二、观察者模式在源码中运用
- Java 中的 java.util.Observer 和 java.util.Observable
- Observer和Observable的使用
- Observer和Observable的源码实现
- Spring 框架中的事件机制
- Spring事件机制的使用
- Spring的事件机质的源码实现
- 三、总结
- 观察者模式的优点
- 观察者模式的缺点
- 观察者模式的适用场景
- 参考
观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会收到通知并自动更新。
假设我们正在开发一个天气预报系统,其中:
当气象站的数据更新时,所有显示设备都需要实时更新显示内容。
下面是没有观察者模式时的实现:
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);
}
}
}
紧耦合
如果没有观察者模式,气象站需要直接知道所有显示设备的存在,并手动调用它们的更新方法。例如:
问题:
难以动态管理依赖
如果显示设备需要动态添加或移除(比如用户关闭了某个显示设备),气象站需要手动管理这些设备的引用。
扩展性差
如果未来需要支持更多类型的观察者(比如日志记录器、报警系统等),气象站的代码会变得越来越臃肿,难以维护。
在观察者模式中有如下角色:
【案例】天气站 - 改
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;
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public 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 {
@Override
public void update(float temperature, float humidity) {
System.out.println("手机显示:温度 = " + temperature + ",湿度 = " + humidity);
}
}
class TVDisplay implements Observer {
@Override
public 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 标准库中提供了观察者模式的实现,分别是 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 {
@Override
public 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 o
:被观察的对象(主题)和 Object arg
:传递给观察者的额外参数(可选)。
public interface Observer {
void update(Observable o, Object arg);
}
主题:Observable
类。
我们可以看到Vector
存储观察者列表。并且因为加了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 框架中的事件机制是基于观察者模式实现的。它允许开发者定义自定义事件,并通过监听器(观察者)来处理这些事件。
自定义事件
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> {
@Override
public 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 事件机制的核心组件包括:
ApplicationEvent
:事件的基类,所有自定义事件都需要继承它。对应观察者模式中的“事件”。ApplicationListener
:观察者接口,定义了处理事件的方法。对应观察者模式中的“观察者”。ApplicationEventPublisher
:事件发布者接口,用于发布事件。对应观察者模式中的“主题”。ApplicationEventMulticaster
:事件广播器,负责将事件分发给所有监听器。类似于观察者模式中的“通知机制”。ApplicationEvent
类:ApplicationEvent
是所有事件的基类,它继承自 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);
}
SimpleApplicationEventMulticaster
类:SimpleApplicationEventMulticaster
是ApplicationEventMulticaster
的默认实现类。
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
// 遍历所有监听器,并调用 onApplicationEvent 方法。
@Override
public 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)之间是松耦合的(主题不需要知道观察者的具体实现,只需要知道观察者接口,观察者也不需要知道主题的具体实现,只需要实现观察者接口)
动态管理依赖:观察者可以动态注册和注销,而不需要修改主题的代码。支持运行时动态添加或移除观察者,灵活性高。
符合开闭原则:可以轻松添加新的观察者,而不需要修改主题的代码。主题的代码不需要因为观察者的变化而修改。
广播通信:主题可以一次性通知所有观察者,适合一对多的通信场景。观察者可以根据需要选择是否响应通知。
职责分离:主题负责维护状态和通知观察者。观察者负责处理状态变化的逻辑。职责分离使得代码更加清晰和可维护。
黑马程序员Java设计模式详解, 23种Java设计模式(图解+框架源码分析+实战)_哔哩哔哩_bilibili