设计模式之观察者模式详解

68 阅读15分钟

深入理解设计模式之观察者模式(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观察BB观察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 核心要点

  1. 观察者模式的本质:定义对象间的一对多依赖,当一个对象状态改变时,所有依赖者都得到通知
  2. 两种模型
    • 推模型:主题推送数据给观察者
    • 拉模型:观察者主动从主题拉取数据
  3. 适用场景
    • 事件监听系统
    • 消息发布订阅
    • 数据绑定
    • 监控告警系统

8.2 使用建议

选择观察者模式的检查清单:

✓ 一个对象的改变需要通知其他对象?
✓ 不知道具体有多少对象需要通知?
✓ 需要解耦主题和观察者?
✓ 需要动态添加/移除观察者?

如果以上都是"是",那么观察者模式是个好选择!

8.3 与其他模式的对比

观察者 vs 发布-订阅:
- 观察者:主题直接通知观察者
- 发布-订阅:通过消息中间件解耦

观察者 vs 中介者:
- 观察者:一对多关系
- 中介者:多对多关系

8.4 实践经验

  1. 考虑使用事件总线:如Guava EventBus、Spring Events
  2. 异步处理:避免阻塞主线程
  3. 注意内存泄漏:及时移除观察者或使用弱引用
  4. 处理异常:一个观察者失败不应影响其他观察者