深入理解设计模式之观察者模式(Observer Pattern)
一、引言
在软件开发中,我们经常会遇到这样的场景:一个对象的状态发生改变时,需要通知所有依赖它的对象。比如,股票价格变化时通知所有股民;订单状态改变时通知用户、仓库、物流等多个系统;微信公众号发布新文章时通知所有订阅者。如果让对象之间直接相互引用,会造成紧耦合,难以维护和扩展。
观察者模式为这类问题提供了优雅的解决方案。它就像现实中的订阅机制:你订阅了某个公众号,当公众号发布新内容时,你会收到通知;你不需要时刻主动查看,公众号也不需要知道你是谁,只需要在有新内容时推送给所有订阅者。
本文将深入探讨观察者模式的原理、实现方式,并结合Spring事件机制、JDK Observable、Guava EventBus等框架应用,帮助你全面掌握这一重要的设计模式。
二、什么是观察者模式
2.1 定义
观察者模式(Observer Pattern)是一种行为型设计模式,它定义对象间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
2.2 核心思想
- 发布-订阅:主题(Subject)发布消息,观察者(Observer)订阅消息
- 松耦合:主题和观察者之间是抽象耦合
- 广播通信:一个主题可以有多个观察者
- 自动通知:状态改变时自动通知所有观察者
2.3 模式结构
┌─────────────────────────┐
│ <<interface>> │
│ Subject │ 抽象主题
├─────────────────────────┤
│ + attach(Observer) │ 注册观察者
│ + detach(Observer) │ 移除观察者
│ + notify() │ 通知所有观察者
└───────────┬─────────────┘
△
│ 实现
┌──────┴──────┐
│ │
┌────┴──────────┐ │
│ConcreteSubject│ │ 具体主题
├───────────────┤ │
│- state │ │
│+ getState() │ │
│+ setState() │ │
└───────────────┘ │
│
┌──────┘
│ 持有
▼
┌─────────────────────────┐
│ <<interface>> │
│ Observer │ 抽象观察者
├─────────────────────────┤
│ + update() │ 更新方法
└───────────┬─────────────┘
△
│ 实现
┌──────┴──────────┐
│ │
┌────┴──────────┐ ┌───┴──────────┐
│ConcreteObserverA ConcreteObserverB│ 具体观察者
└────────────────┘ └───────────────┘
通知流程:
Subject.setState() → notify() → Observer1.update()
→ Observer2.update()
→ Observer3.update()
2.4 观察者模式的两种实现
推模型(Push Model):
Subject → update(data) → Observer
主题推送数据给观察者
拉模型(Pull Model):
Subject → update() → Observer
↓
Observer → getState() → Subject
观察者主动拉取数据
三、基础示例
3.1 场景:天气站
经典的观察者模式示例:气象站发布天气数据,多个显示设备订阅并显示。
抽象主题:
import java.util.ArrayList;
import java.util.List;
/**
* 抽象主题:被观察者
*/
public interface Subject {
/**
* 注册观察者
*/
void registerObserver(Observer observer);
/**
* 移除观察者
*/
void removeObserver(Observer observer);
/**
* 通知所有观察者
*/
void notifyObservers();
}
抽象观察者:
/**
* 抽象观察者
*/
public interface Observer {
/**
* 更新方法
* @param temperature 温度
* @param humidity 湿度
* @param pressure 气压
*/
void update(float temperature, float humidity, float pressure);
}
具体主题:
/**
* 具体主题:气象站
*/
public class WeatherStation implements Subject {
private List<Observer> observers;
private float temperature; // 温度
private float humidity; // 湿度
private float pressure; // 气压
public WeatherStation() {
this.observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer observer) {
if (!observers.contains(observer)) {
observers.add(observer);
System.out.println("[WeatherStation] 新增观察者: " + observer.getClass().getSimpleName());
}
}
@Override
public void removeObserver(Observer observer) {
if (observers.remove(observer)) {
System.out.println("[WeatherStation] 移除观察者: " + observer.getClass().getSimpleName());
}
}
@Override
public void notifyObservers() {
System.out.println("\n[WeatherStation] 通知所有观察者,共 " + observers.size() + " 个");
for (Observer observer : observers) {
observer.update(temperature, humidity, pressure);
}
}
/**
* 气象数据改变
*/
public void setMeasurements(float temperature, float humidity, float pressure) {
System.out.println("\n========== 气象数据更新 ==========");
System.out.println("温度: " + temperature + "°C");
System.out.println("湿度: " + humidity + "%");
System.out.println("气压: " + pressure + " hPa");
System.out.println("================================");
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
// 数据改变,通知观察者
notifyObservers();
}
// Getters
public float getTemperature() { return temperature; }
public float getHumidity() { return humidity; }
public float getPressure() { return pressure; }
}
具体观察者:
/**
* 具体观察者1:当前天气显示
*/
public class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
display();
}
public void display() {
System.out.println("\n[当前天气显示]");
System.out.println(" 温度: " + temperature + "°C");
System.out.println(" 湿度: " + humidity + "%");
}
}
/**
* 具体观察者2:天气统计
*/
public class StatisticsDisplay implements Observer {
private List<Float> temperatureHistory = new ArrayList<>();
@Override
public void update(float temperature, float humidity, float pressure) {
temperatureHistory.add(temperature);
display();
}
public void display() {
float avg = (float) temperatureHistory.stream()
.mapToDouble(Float::doubleValue)
.average()
.orElse(0.0);
float max = (float) temperatureHistory.stream()
.mapToDouble(Float::doubleValue)
.max()
.orElse(0.0);
float min = (float) temperatureHistory.stream()
.mapToDouble(Float::doubleValue)
.min()
.orElse(0.0);
System.out.println("\n[天气统计]");
System.out.println(" 平均温度: " + String.format("%.1f", avg) + "°C");
System.out.println(" 最高温度: " + max + "°C");
System.out.println(" 最低温度: " + min + "°C");
}
}
/**
* 具体观察者3:天气预报
*/
public class ForecastDisplay implements Observer {
private float currentPressure = 1013.0f;
private float lastPressure;
@Override
public void update(float temperature, float humidity, float pressure) {
lastPressure = currentPressure;
currentPressure = pressure;
display();
}
public void display() {
System.out.println("\n[天气预报]");
if (currentPressure > lastPressure) {
System.out.println(" 天气转好");
} else if (currentPressure < lastPressure) {
System.out.println(" 可能下雨");
} else {
System.out.println(" 天气稳定");
}
}
}
客户端使用:
public class WeatherStationDemo {
public static void main(String[] args) {
// 创建气象站(主题)
WeatherStation weatherStation = new WeatherStation();
// 创建观察者
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay();
StatisticsDisplay statisticsDisplay = new StatisticsDisplay();
ForecastDisplay forecastDisplay = new ForecastDisplay();
// 注册观察者
weatherStation.registerObserver(currentDisplay);
weatherStation.registerObserver(statisticsDisplay);
weatherStation.registerObserver(forecastDisplay);
// 模拟气象数据更新
weatherStation.setMeasurements(25.0f, 65.0f, 1013.0f);
System.out.println("\n\n");
weatherStation.setMeasurements(28.0f, 70.0f, 1012.0f);
System.out.println("\n\n");
// 移除一个观察者
weatherStation.removeObserver(forecastDisplay);
weatherStation.setMeasurements(22.0f, 90.0f, 1010.0f);
}
}
四、实际生产场景应用
4.1 场景:订单状态监听系统
在电商系统中,订单状态改变时需要通知多个系统:用户通知、库存系统、物流系统、财务系统等。
/**
* 订单状态枚举
*/
enum OrderStatus {
CREATED("已创建"),
PAID("已支付"),
SHIPPED("已发货"),
DELIVERED("已送达"),
CANCELLED("已取消");
private String description;
OrderStatus(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
/**
* 订单事件
*/
class OrderEvent {
private String orderId;
private OrderStatus status;
private long timestamp;
public OrderEvent(String orderId, OrderStatus status) {
this.orderId = orderId;
this.status = status;
this.timestamp = System.currentTimeMillis();
}
// Getters
public String getOrderId() { return orderId; }
public OrderStatus getStatus() { return status; }
public long getTimestamp() { return timestamp; }
}
/**
* 订单监听器接口
*/
interface OrderListener {
/**
* 订单状态改变时触发
*/
void onOrderStatusChanged(OrderEvent event);
}
/**
* 订单主题
*/
class OrderSubject {
private List<OrderListener> listeners = new ArrayList<>();
/**
* 注册监听器
*/
public void addListener(OrderListener listener) {
listeners.add(listener);
}
/**
* 移除监听器
*/
public void removeListener(OrderListener listener) {
listeners.remove(listener);
}
/**
* 通知所有监听器
*/
private void notifyListeners(OrderEvent event) {
System.out.println("\n[订单系统] 通知 " + listeners.size() + " 个监听器");
for (OrderListener listener : listeners) {
try {
listener.onOrderStatusChanged(event);
} catch (Exception e) {
System.err.println("监听器执行失败: " + e.getMessage());
}
}
}
/**
* 更新订单状态
*/
public void updateOrderStatus(String orderId, OrderStatus status) {
System.out.println("\n========================================");
System.out.println("[订单系统] 订单状态更新");
System.out.println(" 订单号: " + orderId);
System.out.println(" 新状态: " + status.getDescription());
System.out.println("========================================");
// 创建事件并通知
OrderEvent event = new OrderEvent(orderId, status);
notifyListeners(event);
}
}
具体监听器:
/**
* 用户通知监听器
*/
class UserNotificationListener implements OrderListener {
@Override
public void onOrderStatusChanged(OrderEvent event) {
System.out.println("\n[用户通知服务]");
switch (event.getStatus()) {
case PAID:
sendNotification(event.getOrderId(), "您的订单已支付成功!");
break;
case SHIPPED:
sendNotification(event.getOrderId(), "您的订单已发货,请注意查收!");
break;
case DELIVERED:
sendNotification(event.getOrderId(), "您的订单已送达,感谢购买!");
break;
case CANCELLED:
sendNotification(event.getOrderId(), "您的订单已取消");
break;
}
}
private void sendNotification(String orderId, String message) {
System.out.println(" 发送通知: " + message);
// 实际实现:发送短信、推送、邮件等
}
}
/**
* 库存系统监听器
*/
class InventoryListener implements OrderListener {
@Override
public void onOrderStatusChanged(OrderEvent event) {
System.out.println("\n[库存系统]");
switch (event.getStatus()) {
case PAID:
lockInventory(event.getOrderId());
break;
case CANCELLED:
releaseInventory(event.getOrderId());
break;
}
}
private void lockInventory(String orderId) {
System.out.println(" 锁定库存: " + orderId);
}
private void releaseInventory(String orderId) {
System.out.println(" 释放库存: " + orderId);
}
}
/**
* 物流系统监听器
*/
class LogisticsListener implements OrderListener {
@Override
public void onOrderStatusChanged(OrderEvent event) {
System.out.println("\n[物流系统]");
switch (event.getStatus()) {
case PAID:
createShippingOrder(event.getOrderId());
break;
case CANCELLED:
cancelShippingOrder(event.getOrderId());
break;
}
}
private void createShippingOrder(String orderId) {
System.out.println(" 创建物流单: " + orderId);
}
private void cancelShippingOrder(String orderId) {
System.out.println(" 取消物流单: " + orderId);
}
}
/**
* 财务系统监听器
*/
class FinanceListener implements OrderListener {
@Override
public void onOrderStatusChanged(OrderEvent event) {
System.out.println("\n[财务系统]");
switch (event.getStatus()) {
case PAID:
recordIncome(event.getOrderId());
break;
case CANCELLED:
processRefund(event.getOrderId());
break;
}
}
private void recordIncome(String orderId) {
System.out.println(" 记录收入: " + orderId);
}
private void processRefund(String orderId) {
System.out.println(" 处理退款: " + orderId);
}
}
/**
* 数据分析监听器
*/
class AnalyticsListener implements OrderListener {
@Override
public void onOrderStatusChanged(OrderEvent event) {
System.out.println("\n[数据分析]");
System.out.println(" 记录订单状态变更数据");
System.out.println(" 更新实时报表");
}
}
客户端使用:
public class OrderSystemDemo {
public static void main(String[] args) {
// 创建订单主题
OrderSubject orderSubject = new OrderSubject();
// 注册各个系统的监听器
orderSubject.addListener(new UserNotificationListener());
orderSubject.addListener(new InventoryListener());
orderSubject.addListener(new LogisticsListener());
orderSubject.addListener(new FinanceListener());
orderSubject.addListener(new AnalyticsListener());
// 模拟订单状态变化
String orderId = "ORDER20250119001";
// 订单支付
orderSubject.updateOrderStatus(orderId, OrderStatus.PAID);
// 等待一段时间
sleep(1000);
// 订单发货
orderSubject.updateOrderStatus(orderId, OrderStatus.SHIPPED);
sleep(1000);
// 订单送达
orderSubject.updateOrderStatus(orderId, OrderStatus.DELIVERED);
System.out.println("\n\n========== 测试取消订单 ==========");
String orderId2 = "ORDER20250119002";
orderSubject.updateOrderStatus(orderId2, OrderStatus.PAID);
sleep(500);
orderSubject.updateOrderStatus(orderId2, OrderStatus.CANCELLED);
}
private static void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
4.2 场景:监控告警系统
系统监控需要在指标异常时通知多个渠道:邮件、短信、钉钉、企业微信等。
/**
* 告警级别
*/
enum AlertLevel {
INFO("信息"),
WARNING("警告"),
ERROR("错误"),
CRITICAL("严重");
private String description;
AlertLevel(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
/**
* 告警事件
*/
class AlertEvent {
private String metricName; // 指标名称
private double value; // 当前值
private double threshold; // 阈值
private AlertLevel level; // 告警级别
private String message; // 告警消息
private long timestamp;
public AlertEvent(String metricName, double value, double threshold,
AlertLevel level, String message) {
this.metricName = metricName;
this.value = value;
this.threshold = threshold;
this.level = level;
this.message = message;
this.timestamp = System.currentTimeMillis();
}
// Getters
public String getMetricName() { return metricName; }
public double getValue() { return value; }
public double getThreshold() { return threshold; }
public AlertLevel getLevel() { return level; }
public String getMessage() { return message; }
public long getTimestamp() { return timestamp; }
}
/**
* 告警监听器
*/
interface AlertListener {
/**
* 处理告警
*/
void onAlert(AlertEvent event);
/**
* 是否支持该级别的告警
*/
boolean supports(AlertLevel level);
}
/**
* 监控系统
*/
class MonitoringSystem {
private List<AlertListener> listeners = new ArrayList<>();
public void addListener(AlertListener listener) {
listeners.add(listener);
}
public void removeListener(AlertListener listener) {
listeners.remove(listener);
}
/**
* 触发告警
*/
public void triggerAlert(AlertEvent event) {
System.out.println("\n========================================");
System.out.println("[监控系统] 触发告警");
System.out.println(" 指标: " + event.getMetricName());
System.out.println(" 当前值: " + event.getValue());
System.out.println(" 阈值: " + event.getThreshold());
System.out.println(" 级别: " + event.getLevel().getDescription());
System.out.println(" 消息: " + event.getMessage());
System.out.println("========================================");
// 通知监听器
for (AlertListener listener : listeners) {
if (listener.supports(event.getLevel())) {
try {
listener.onAlert(event);
} catch (Exception e) {
System.err.println("告警发送失败: " + e.getMessage());
}
}
}
}
/**
* 检查指标
*/
public void checkMetric(String metricName, double value, double threshold) {
if (value > threshold) {
AlertLevel level;
if (value > threshold * 2) {
level = AlertLevel.CRITICAL;
} else if (value > threshold * 1.5) {
level = AlertLevel.ERROR;
} else {
level = AlertLevel.WARNING;
}
String message = String.format("%s 超过阈值!当前值: %.2f, 阈值: %.2f",
metricName, value, threshold);
triggerAlert(new AlertEvent(metricName, value, threshold, level, message));
}
}
}
/**
* 邮件告警监听器
*/
class EmailAlertListener implements AlertListener {
@Override
public void onAlert(AlertEvent event) {
System.out.println("\n[邮件告警]");
System.out.println(" 发送邮件到: ops@example.com");
System.out.println(" 主题: " + event.getLevel().getDescription() + " - " + event.getMetricName());
System.out.println(" 内容: " + event.getMessage());
}
@Override
public boolean supports(AlertLevel level) {
// 邮件支持所有级别
return true;
}
}
/**
* 短信告警监听器
*/
class SmsAlertListener implements AlertListener {
@Override
public void onAlert(AlertEvent event) {
System.out.println("\n[短信告警]");
System.out.println(" 发送短信到: 138****8888");
System.out.println(" 内容: " + event.getMessage());
}
@Override
public boolean supports(AlertLevel level) {
// 短信只发送ERROR和CRITICAL级别
return level == AlertLevel.ERROR || level == AlertLevel.CRITICAL;
}
}
/**
* 钉钉告警监听器
*/
class DingTalkAlertListener implements AlertListener {
@Override
public void onAlert(AlertEvent event) {
System.out.println("\n[钉钉告警]");
System.out.println(" 发送钉钉消息到: 运维群");
System.out.println(" 内容: " + formatMarkdown(event));
}
private String formatMarkdown(AlertEvent event) {
return String.format("### %s告警\n- 指标: %s\n- 当前值: %.2f\n- 阈值: %.2f",
event.getLevel().getDescription(),
event.getMetricName(),
event.getValue(),
event.getThreshold());
}
@Override
public boolean supports(AlertLevel level) {
// 钉钉支持WARNING及以上
return level != AlertLevel.INFO;
}
}
/**
* 电话告警监听器
*/
class PhoneCallAlertListener implements AlertListener {
@Override
public void onAlert(AlertEvent event) {
System.out.println("\n[电话告警]");
System.out.println(" 拨打电话: 138****8888");
System.out.println(" 语音播报: " + event.getMessage());
}
@Override
public boolean supports(AlertLevel level) {
// 电话只用于CRITICAL级别
return level == AlertLevel.CRITICAL;
}
}
/**
* 测试监控告警系统
*/
class MonitoringSystemDemo {
public static void main(String[] args) {
// 创建监控系统
MonitoringSystem monitoring = new MonitoringSystem();
// 注册告警监听器
monitoring.addListener(new EmailAlertListener());
monitoring.addListener(new SmsAlertListener());
monitoring.addListener(new DingTalkAlertListener());
monitoring.addListener(new PhoneCallAlertListener());
// 模拟监控指标检查
System.out.println("========== 场景1:CPU使用率略高(WARNING) ==========");
monitoring.checkMetric("CPU使用率", 75.0, 50.0);
System.out.println("\n\n========== 场景2:内存使用率很高(ERROR) ==========");
monitoring.checkMetric("内存使用率", 88.0, 50.0);
System.out.println("\n\n========== 场景3:磁盘使用率极高(CRITICAL) ==========");
monitoring.checkMetric("磁盘使用率", 98.0, 80.0);
}
}
五、开源框架中的应用
5.1 JDK的Observable/Observer
Java内置的观察者模式实现(已在Java 9中标记为过时)。
import java.util.Observable;
import java.util.Observer;
/**
* JDK内置的Observable/Observer
* 注意:Java 9后已被标记为@Deprecated
*/
/**
* 具体主题:继承Observable
*/
class StockData extends Observable {
private String stockName;
private double price;
public StockData(String stockName) {
this.stockName = stockName;
}
public void setPrice(double price) {
this.price = price;
// 标记状态已改变
setChanged();
// 通知观察者(推模型)
notifyObservers(price);
}
public String getStockName() {
return stockName;
}
public double getPrice() {
return price;
}
}
/**
* 具体观察者:实现Observer接口
*/
class StockDisplay implements Observer {
private String displayName;
public StockDisplay(String displayName) {
this.displayName = displayName;
}
@Override
public void update(Observable o, Object arg) {
if (o instanceof StockData) {
StockData stock = (StockData) o;
double price = (Double) arg;
System.out.println("[" + displayName + "] " +
stock.getStockName() + " 价格更新: ¥" + price);
}
}
}
/**
* 测试JDK Observable
*/
class JdkObservableDemo {
public static void main(String[] args) {
// 创建股票数据(主题)
StockData appleStock = new StockData("苹果股票");
// 创建观察者
StockDisplay display1 = new StockDisplay("终端1");
StockDisplay display2 = new StockDisplay("终端2");
StockDisplay display3 = new StockDisplay("手机APP");
// 注册观察者
appleStock.addObserver(display1);
appleStock.addObserver(display2);
appleStock.addObserver(display3);
// 更新价格
System.out.println("===== 第一次更新 =====");
appleStock.setPrice(150.50);
System.out.println("\n===== 第二次更新 =====");
appleStock.setPrice(152.30);
// 移除一个观察者
appleStock.deleteObserver(display2);
System.out.println("\n===== 第三次更新(display2已移除) =====");
appleStock.setPrice(148.90);
}
}
5.2 Spring事件机制
Spring框架的ApplicationEvent是观察者模式的优秀实现。
/**
* Spring事件机制(简化模拟)
*
* Spring的事件机制基于观察者模式:
* - ApplicationEvent: 事件
* - ApplicationListener: 监听器
* - ApplicationEventPublisher: 事件发布器
*/
/**
* 自定义事件:用户注册事件
*/
// 在真实Spring中继承ApplicationEvent
class UserRegisteredEvent {
private String username;
private String email;
private long timestamp;
public UserRegisteredEvent(String username, String email) {
this.username = username;
this.email = email;
this.timestamp = System.currentTimeMillis();
}
// Getters
public String getUsername() { return username; }
public String getEmail() { return email; }
public long getTimestamp() { return timestamp; }
}
/**
* 事件监听器接口
*/
interface ApplicationListener<E> {
void onApplicationEvent(E event);
}
/**
* 事件发布器
*/
class ApplicationEventPublisher {
private List<ApplicationListener> listeners = new ArrayList<>();
public void addListener(ApplicationListener listener) {
listeners.add(listener);
}
@SuppressWarnings("unchecked")
public void publishEvent(Object event) {
System.out.println("\n[EventPublisher] 发布事件: " + event.getClass().getSimpleName());
for (ApplicationListener listener : listeners) {
try {
listener.onApplicationEvent(event);
} catch (Exception e) {
System.err.println("监听器执行失败: " + e.getMessage());
}
}
}
}
/**
* 监听器1:发送欢迎邮件
*/
class WelcomeEmailListener implements ApplicationListener<UserRegisteredEvent> {
@Override
public void onApplicationEvent(UserRegisteredEvent event) {
System.out.println("\n[WelcomeEmailListener] 处理用户注册事件");
System.out.println(" 发送欢迎邮件到: " + event.getEmail());
System.out.println(" 邮件内容: 欢迎 " + event.getUsername() + " 注册!");
}
}
/**
* 监听器2:赠送优惠券
*/
class CouponListener implements ApplicationListener<UserRegisteredEvent> {
@Override
public void onApplicationEvent(UserRegisteredEvent event) {
System.out.println("\n[CouponListener] 处理用户注册事件");
System.out.println(" 为用户 " + event.getUsername() + " 发放新人优惠券");
System.out.println(" 优惠券: 满100减20");
}
}
/**
* 监听器3:记录用户行为
*/
class UserBehaviorListener implements ApplicationListener<UserRegisteredEvent> {
@Override
public void onApplicationEvent(UserRegisteredEvent event) {
System.out.println("\n[UserBehaviorListener] 处理用户注册事件");
System.out.println(" 记录用户行为数据");
System.out.println(" 用户: " + event.getUsername());
System.out.println(" 时间: " + new java.util.Date(event.getTimestamp()));
}
}
/**
* 用户服务
*/
class UserService {
private ApplicationEventPublisher eventPublisher;
public UserService(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
/**
* 用户注册
*/
public void register(String username, String email) {
System.out.println("========================================");
System.out.println("[UserService] 用户注册");
System.out.println(" 用户名: " + username);
System.out.println(" 邮箱: " + email);
System.out.println("========================================");
// 1. 保存用户到数据库
saveUser(username, email);
// 2. 发布用户注册事件
UserRegisteredEvent event = new UserRegisteredEvent(username, email);
eventPublisher.publishEvent(event);
System.out.println("\n[UserService] 用户注册完成\n");
}
private void saveUser(String username, String email) {
System.out.println(" 保存用户到数据库...");
}
}
/**
* 测试Spring事件机制
*/
class SpringEventDemo {
public static void main(String[] args) {
// 创建事件发布器
ApplicationEventPublisher publisher = new ApplicationEventPublisher();
// 注册监听器(在Spring中通过@EventListener或实现接口自动注册)
publisher.addListener(new WelcomeEmailListener());
publisher.addListener(new CouponListener());
publisher.addListener(new UserBehaviorListener());
// 创建用户服务
UserService userService = new UserService(publisher);
// 用户注册(会触发事件)
userService.register("张三", "zhangsan@example.com");
// 再注册一个用户
userService.register("李四", "lisi@example.com");
}
}
/**
* 在真实的Spring中使用:
*
* // 1. 定义事件
* public class UserRegisteredEvent extends ApplicationEvent {
* private String username;
* // ...
* }
*
* // 2. 定义监听器
* @Component
* public class WelcomeEmailListener {
* @EventListener
* public void handleUserRegistered(UserRegisteredEvent event) {
* // 处理事件
* }
* }
*
* // 3. 发布事件
* @Service
* public class UserService {
* @Autowired
* private ApplicationEventPublisher publisher;
*
* public void register(String username) {
* // 业务逻辑
* publisher.publishEvent(new UserRegisteredEvent(username));
* }
* }
*/
5.3 Guava EventBus
Google Guava提供的轻量级事件总线。
/**
* Guava EventBus简化实现
*
* EventBus特点:
* 1. 使用注解@Subscribe标记订阅方法
* 2. 支持同步和异步事件
* 3. 自动根据事件类型分发
*/
import java.lang.annotation.*;
import java.lang.reflect.Method;
/**
* Subscribe注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Subscribe {
}
/**
* 简化的EventBus实现
*/
class SimpleEventBus {
private Map<Class<?>, List<SubscriberMethod>> subscribers = new java.util.HashMap<>();
/**
* 注册订阅者
*/
public void register(Object subscriber) {
Class<?> clazz = subscriber.getClass();
System.out.println("[EventBus] 注册订阅者: " + clazz.getSimpleName());
// 查找带@Subscribe注解的方法
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(Subscribe.class)) {
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
Class<?> eventType = parameterTypes[0];
subscribers.computeIfAbsent(eventType, k -> new ArrayList<>())
.add(new SubscriberMethod(subscriber, method));
System.out.println(" - 订阅事件: " + eventType.getSimpleName() +
", 方法: " + method.getName());
}
}
}
}
/**
* 发布事件
*/
public void post(Object event) {
Class<?> eventType = event.getClass();
System.out.println("\n[EventBus] 发布事件: " + eventType.getSimpleName());
List<SubscriberMethod> methods = subscribers.get(eventType);
if (methods != null) {
for (SubscriberMethod method : methods) {
try {
method.invoke(event);
} catch (Exception e) {
System.err.println("事件处理失败: " + e.getMessage());
}
}
} else {
System.out.println(" 没有订阅者");
}
}
/**
* 订阅方法封装
*/
private static class SubscriberMethod {
private Object subscriber;
private Method method;
public SubscriberMethod(Object subscriber, Method method) {
this.subscriber = subscriber;
this.method = method;
}
public void invoke(Object event) throws Exception {
method.invoke(subscriber, event);
}
}
}
/**
* 事件:订单创建事件
*/
class OrderCreatedEvent {
private String orderId;
private double amount;
public OrderCreatedEvent(String orderId, double amount) {
this.orderId = orderId;
this.amount = amount;
}
public String getOrderId() { return orderId; }
public double getAmount() { return amount; }
}
/**
* 订阅者:订单服务
*/
class OrderEventSubscriber {
@Subscribe
public void handleOrderCreated(OrderCreatedEvent event) {
System.out.println("\n[OrderEventSubscriber] 处理订单创建");
System.out.println(" 订单号: " + event.getOrderId());
System.out.println(" 金额: ¥" + event.getAmount());
}
}
/**
* 订阅者:积分服务
*/
class PointsEventSubscriber {
@Subscribe
public void handleOrderCreated(OrderCreatedEvent event) {
System.out.println("\n[PointsEventSubscriber] 处理订单创建");
int points = (int) (event.getAmount() / 10);
System.out.println(" 赠送积分: " + points);
}
}
/**
* 订阅者:营销服务
*/
class MarketingEventSubscriber {
@Subscribe
public void handleOrderCreated(OrderCreatedEvent event) {
System.out.println("\n[MarketingEventSubscriber] 处理订单创建");
System.out.println(" 记录用户购买行为");
System.out.println(" 更新用户画像");
}
}
/**
* 测试EventBus
*/
class EventBusDemo {
public static void main(String[] args) {
// 创建EventBus
SimpleEventBus eventBus = new SimpleEventBus();
// 注册订阅者
eventBus.register(new OrderEventSubscriber());
eventBus.register(new PointsEventSubscriber());
eventBus.register(new MarketingEventSubscriber());
System.out.println("\n" + "=".repeat(50));
// 发布事件
OrderCreatedEvent event = new OrderCreatedEvent("ORDER001", 299.00);
eventBus.post(event);
}
}
/**
* 在真实的Guava EventBus中使用:
*
* // 1. 创建EventBus
* EventBus eventBus = new EventBus();
*
* // 2. 定义订阅者
* public class OrderSubscriber {
* @Subscribe
* public void handleOrderCreated(OrderCreatedEvent event) {
* // 处理事件
* }
* }
*
* // 3. 注册和发布
* eventBus.register(new OrderSubscriber());
* eventBus.post(new OrderCreatedEvent());
*
* // 4. 异步EventBus
* EventBus asyncBus = new AsyncEventBus(Executors.newFixedThreadPool(4));
*/
六、观察者模式的优缺点
6.1 优点
1. 解耦
主题和观察者之间是抽象耦合
┌─────────┐ ┌──────────┐
│ Subject │────────▶│ Observer │
└─────────┘ └──────────┘
(接口) (接口)
主题不需要知道观察者的具体实现
2. 支持广播通信
一个主题可以通知多个观察者
Subject → Observer1
→ Observer2
→ Observer3
→ ...
3. 符合开闭原则
添加新观察者:无需修改主题代码
移除观察者:不影响其他观察者
4. 建立触发机制
状态改变自动触发通知
无需主动轮询
6.2 缺点
1. 性能问题
观察者过多:通知耗时增加
顺序执行:一个观察者阻塞影响其他
2. 内存泄漏风险
忘记移除观察者:导致对象无法被回收
使用弱引用:可以缓解问题
3. 循环依赖
A观察B,B观察A
可能导致死循环
4. 顺序不确定
观察者执行顺序不保证
可能导致依赖问题
七、最佳实践
7.1 异步通知
/**
* 异步观察者模式
*/
class AsyncSubject {
private List<Observer> observers = new ArrayList<>();
private java.util.concurrent.ExecutorService executor =
java.util.concurrent.Executors.newFixedThreadPool(4);
public void addObserver(Observer observer) {
observers.add(observer);
}
/**
* 异步通知所有观察者
*/
public void notifyObserversAsync(float temperature, float humidity, float pressure) {
System.out.println("[AsyncSubject] 开始异步通知 " + observers.size() + " 个观察者");
for (Observer observer : observers) {
executor.submit(() -> {
try {
observer.update(temperature, humidity, pressure);
} catch (Exception e) {
System.err.println("观察者执行失败: " + e.getMessage());
}
});
}
}
public void shutdown() {
executor.shutdown();
}
}
7.2 使用弱引用避免内存泄漏
import java.lang.ref.WeakReference;
/**
* 使用弱引用的主题
*/
class WeakReferenceSubject {
private List<WeakReference<Observer>> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(new WeakReference<>(observer));
}
public void notifyObservers(float temperature, float humidity, float pressure) {
// 清理已被回收的观察者
observers.removeIf(ref -> ref.get() == null);
// 通知剩余观察者
for (WeakReference<Observer> ref : observers) {
Observer observer = ref.get();
if (observer != null) {
observer.update(temperature, humidity, pressure);
}
}
}
}
7.3 支持优先级
/**
* 带优先级的观察者
*/
class PriorityObserver implements Observer, Comparable<PriorityObserver> {
private int priority;
private Observer delegate;
public PriorityObserver(Observer delegate, int priority) {
this.delegate = delegate;
this.priority = priority;
}
@Override
public void update(float temperature, float humidity, float pressure) {
delegate.update(temperature, humidity, pressure);
}
@Override
public int compareTo(PriorityObserver other) {
return Integer.compare(other.priority, this.priority); // 降序
}
}
/**
* 支持优先级的主题
*/
class PrioritySubject {
private java.util.PriorityQueue<PriorityObserver> observers =
new java.util.PriorityQueue<>();
public void addObserver(Observer observer, int priority) {
observers.add(new PriorityObserver(observer, priority));
}
public void notifyObservers(float temperature, float humidity, float pressure) {
// 按优先级通知
for (PriorityObserver observer : observers) {
observer.update(temperature, humidity, pressure);
}
}
}
八、总结
8.1 核心要点
- 观察者模式的本质:定义对象间的一对多依赖,当一个对象状态改变时,所有依赖者都得到通知
- 两种模型:
- 推模型:主题推送数据给观察者
- 拉模型:观察者主动从主题拉取数据
- 适用场景:
- 事件监听系统
- 消息发布订阅
- 数据绑定
- 监控告警系统
8.2 使用建议
选择观察者模式的检查清单:
✓ 一个对象的改变需要通知其他对象?
✓ 不知道具体有多少对象需要通知?
✓ 需要解耦主题和观察者?
✓ 需要动态添加/移除观察者?
如果以上都是"是",那么观察者模式是个好选择!
8.3 与其他模式的对比
观察者 vs 发布-订阅:
- 观察者:主题直接通知观察者
- 发布-订阅:通过消息中间件解耦
观察者 vs 中介者:
- 观察者:一对多关系
- 中介者:多对多关系
8.4 实践经验
- 考虑使用事件总线:如Guava EventBus、Spring Events
- 异步处理:避免阻塞主线程
- 注意内存泄漏:及时移除观察者或使用弱引用
- 处理异常:一个观察者失败不应影响其他观察者