模式定义

观察者模式是一种行为型设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。观察者模式又被称为发布-订阅模式,是实现对象间一对多依赖关系的常用设计模式。

模式结构

graph TD A[Subject] --> B[Observer] A --> C[ConcreteObserver] A --> D[ConcreteObserver]

实现方式

基础实现

定义主题接口和观察者接口,实现具体主题和具体观察者。

// 观察者接口
public interface Observer {
    void update(float temperature, float humidity, float pressure);
}

// 主题接口
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// 具体主题 - 天气数据
class WeatherData implements Subject {
    private List observers;
    private float temperature;
    private float humidity;
    private float pressure;
    
    public WeatherData() {
        observers = new ArrayList<>();
    }
    
    @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, pressure);
        }
    }
    
    // 当气象数据更新时调用
    public void measurementsChanged() {
        notifyObservers();
    }
    
    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }
    
    // getters...
    public float getTemperature() { return temperature; }
    public float getHumidity() { return humidity; }
    public float getPressure() { return pressure; }
}

// 具体观察者 - 当前天气显示
class CurrentConditionsDisplay implements Observer {
    private float temperature;
    private float humidity;
    private Subject weatherData;
    
    public CurrentConditionsDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }
    
    @Override
    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        display();
    }
    
    public void display() {
        System.out.println("当前天气状况: " + temperature + "°C, 湿度: " + humidity + "%");
    }
}

使用示例

public class ObserverPatternDemo {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        
        CurrentConditionsDisplay currentDisplay = 
            new CurrentConditionsDisplay(weatherData);
        
        // 模拟气象数据更新
        weatherData.setMeasurements(25.0f, 65.0f, 30.4f);
        weatherData.setMeasurements(27.0f, 70.0f, 29.2f);
        weatherData.setMeasurements(23.0f, 90.0f, 29.8f);
    }
}

经典案例

1. Java内置Observer模式

Java早期版本提供了Observable类和Observer接口:

// 被观察者
class NewsAgency extends Observable {
    private String news;
    
    public void setNews(String news) {
        this.news = news;
        setChanged(); // 标记状态已改变
        notifyObservers(news); // 通知所有观察者
    }
}

// 观察者
class NewsChannel implements Observer {
    private String news;
    
    @Override
    public void update(Observable agency, Object news) {
        this.news = (String) news;
        System.out.println("新闻频道收到最新消息: " + news);
    }
}

// 使用示例
NewsAgency agency = new NewsAgency();
NewsChannel channel1 = new NewsChannel();
NewsChannel channel2 = new NewsChannel();

agency.addObserver(channel1);
agency.addObserver(channel2);

agency.setNews("重大新闻:设计模式系列教程上线!");

2. Swing事件处理机制

Java Swing中的事件处理是观察者模式的典型应用:

JButton button = new JButton("点击我");

// 添加事件监听器(观察者)
button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("按钮被点击了!");
    }
});

// 当按钮被点击时,会通知所有注册的监听器

3. RxJava响应式编程

RxJava是观察者模式在现代Java中的高级应用:

Observable observable = Observable.just("Hello", "World");

Observer observer = new Observer() {
    @Override
    public void onSubscribe(Disposable d) {
        System.out.println("订阅开始");
    }
    
    @Override
    public void onNext(String s) {
        System.out.println("收到数据: " + s);
    }
    
    @Override
    public void onError(Throwable e) {
        System.err.println("发生错误: " + e.getMessage());
    }
    
    @Override
    public void onComplete() {
        System.out.println("数据流结束");
    }
};

observable.subscribe(observer);

应用场景

优缺点

优点

  • 解耦合:主题和观察者之间松耦合,可以独立变化
  • 支持广播通信:主题可以通知所有观察者,无需指定具体接收者
  • 符合开闭原则:增加新的观察者无需修改主题代码
  • 动态关系:可以在运行时建立和解除观察关系

缺点

  • 性能问题:通知所有观察者可能很耗时
  • 内存泄漏风险:观察者未正确注销可能导致内存泄漏
  • 意外更新:一个观察者的更新可能引起连锁反应
  • 调试困难:对象间的依赖关系可能使调试变得复杂