观察者模式详解
一、观察者模式概述
观察者模式(Observer Pattern)是一种行为型设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会自动收到通知并更新。
核心特点
- 松耦合:主题和观察者之间松耦合
- 自动通知:状态变化时自动通知观察者
- 一对多:一个主题可对应多个观察者
- 动态订阅:可动态添加/删除观察者
二、观察者模式的结构
主要角色
- Subject:主题/被观察者,维护观察者列表
- Observer:观察者接口,定义更新方法
- ConcreteSubject:具体主题,状态变化时通知观察者
- ConcreteObserver:具体观察者,实现更新逻辑
三、观察者模式的实现
1. 基本实现(推模型)
// 观察者接口
public interface Observer {
void update(String message);
}
// 主题接口
public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
// 具体主题 - 新闻发布中心
public class NewsAgency implements Subject {
private List<Observer> observers = new ArrayList<>();
private String news;
public void setNews(String news) {
this.news = news;
notifyObservers();
}
public void registerObserver(Observer o) {
observers.add(o);
}
public void removeObserver(Observer o) {
observers.remove(o);
}
public void notifyObservers() {
for (Observer o : observers) {
o.update(news);
}
}
}
// 具体观察者 - 新闻频道
public class NewsChannel implements Observer {
private String name;
public NewsChannel(String name) {
this.name = name;
}
public void update(String news) {
System.out.println(name + " 收到新闻: " + news);
}
}
// 使用示例
NewsAgency agency = new NewsAgency();
Observer channel1 = new NewsChannel("央视新闻");
Observer channel2 = new NewsChannel("BBC");
agency.registerObserver(channel1);
agency.registerObserver(channel2);
agency.setNews("重大新闻:Java 21发布!");
2. 更灵活的实现(拉模型)
// 增强的观察者接口
public interface EnhancedObserver {
void update(Subject subject);
}
// 增强的主题类
public class WeatherStation implements Subject {
private List<Observer> observers = new ArrayList<>();
private float temperature;
private float humidity;
public void setMeasurements(float temp, float humidity) {
this.temperature = temp;
this.humidity = humidity;
notifyObservers();
}
// getter方法
public float getTemperature() { return temperature; }
public float getHumidity() { return humidity; }
// 其他Subject接口实现...
}
// 具体观察者 - 天气显示
public class CurrentConditionsDisplay implements EnhancedObserver {
public void update(Subject subject) {
if (subject instanceof WeatherStation) {
WeatherStation ws = (WeatherStation) subject;
System.out.printf("当前温度: %.1f°C, 湿度: %.1f%%\n",
ws.getTemperature(), ws.getHumidity());
}
}
}
四、观察者模式的应用场景
1. 事件驱动系统
// 事件管理器
public class EventManager {
private Map<String, List<EventListener>> listeners = new HashMap<>();
public void subscribe(String eventType, EventListener listener) {
listeners.computeIfAbsent(eventType, k -> new ArrayList<>()).add(listener);
}
public void unsubscribe(String eventType, EventListener listener) {
List<EventListener> eventListeners = listeners.get(eventType);
if (eventListeners != null) {
eventListeners.remove(listener);
}
}
public void notify(String eventType, String data) {
List<EventListener> eventListeners = listeners.get(eventType);
if (eventListeners != null) {
for (EventListener listener : eventListeners) {
listener.update(data);
}
}
}
}
2. 股票价格提醒
public class StockMarket {
private Map<String, Double> prices = new HashMap<>();
private List<StockObserver> observers = new ArrayList<>();
public void addObserver(StockObserver o) {
observers.add(o);
}
public void updatePrice(String symbol, double price) {
prices.put(symbol, price);
notifyObservers(symbol, price);
}
private void notifyObservers(String symbol, double price) {
for (StockObserver o : observers) {
o.onPriceChanged(symbol, price);
}
}
}
public interface StockObserver {
void onPriceChanged(String symbol, double price);
}
3. Reactor模式(网络事件)
public class Reactor {
private List<EventHandler> handlers = new ArrayList<>();
public void registerHandler(EventHandler handler) {
handlers.add(handler);
}
public void handleEvents() {
while (true) {
Event event = waitForEvent();
for (EventHandler h : handlers) {
if (h.canHandle(event)) {
h.handle(event);
}
}
}
}
}
五、观察者模式的变体
1. 使用Java内置Observable类(已废弃)
// 不推荐使用,仅作示例
public class ObservableValue extends java.util.Observable {
private int value;
public void setValue(int value) {
this.value = value;
setChanged();
notifyObservers(value);
}
}
2. 使用Java 9+的Flow API
import java.util.concurrent.Flow.*;
public class NewsPublisher implements Publisher<String> {
private SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
public void subscribe(Subscriber<? super String> subscriber) {
publisher.subscribe(subscriber);
}
public void publish(String news) {
publisher.submit(news);
}
}
public class NewsSubscriber implements Subscriber<String> {
private Subscription subscription;
public void onSubscribe(Subscription subscription) {
this.subscription = subscription;
subscription.request(1);
}
public void onNext(String item) {
System.out.println("收到新闻: " + item);
subscription.request(1);
}
// 其他方法实现...
}
六、观察者模式的优缺点
优点
- 解耦:主题和观察者松耦合
- 动态关系:可运行时添加/删除观察者
- 广播通信:一对多通知效率高
- 开闭原则:新增观察者无需修改主题
缺点
- 通知顺序:观察者通知顺序不确定
- 性能问题:观察者过多时通知耗时
- 循环依赖:可能导致循环调用
- 内存泄漏:需手动取消注册
七、最佳实践
- 使用弱引用:防止观察者导致内存泄漏
- 异步通知:耗时观察者使用异步方式
- 批量通知:高频更新可合并通知
- 异常处理:单个观察者异常不应影响其他
- 考虑线程安全:多线程环境下的安全性
八、总结
观察者模式是事件处理的核心模式,特别适用于:
- 需要维护对象间的一致性
- 需要实现事件通知机制
- 对象变化需要通知其他对象
- 需要广播通信的场景
在实际开发中,观察者模式常见于:
- GUI事件处理(如按钮点击)
- 发布-订阅系统
- 实时数据监控
- MVC架构中的模型-视图通信
- 响应式编程框架
正确使用观察者模式可以实现松耦合的设计,但需要注意避免过度使用导致的性能问题。