# Java的观察者模式是什么 ## 目录 1. [观察者模式概述](#观察者模式概述) 2. [模式结构与角色](#模式结构与角色) 3. [Java内置观察者实现](#java内置观察者实现) 4. [自定义观察者模式实现](#自定义观察者模式实现) 5. [推模型与拉模型](#推模型与拉模型) 6. [观察者模式优缺点](#观察者模式优缺点) 7. [典型应用场景](#典型应用场景) 8. [与其他模式的关系](#与其他模式的关系) 9. [JDK中的观察者模式](#jdk中的观察者模式) 10. [Spring框架中的应用](#spring框架中的应用) 11. [实际案例演示](#实际案例演示) 12. [常见问题与解决方案](#常见问题与解决方案) 13. [观察者模式变体](#观察者模式变体) 14. [性能考量](#性能考量) 15. [总结](#总结) <a id="观察者模式概述"></a> ## 1. 观察者模式概述 观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这种模式也被称为发布-订阅(Publish-Subscribe)模式。 ### 1.1 基本概念 在观察者模式中,有两个主要角色: - **Subject(主题)**:被观察的对象,它维护一组观察者,提供添加和删除观察者的方法,并在状态改变时通知观察者 - **Observer(观察者)**:定义了一个更新接口,用于在主题状态改变时接收通知 ### 1.2 模式价值 观察者模式的核心价值在于: - 解耦主题和观察者,使它们可以独立变化 - 支持广播通信,主题无需知道具体有哪些观察者 - 遵循开放-封闭原则,可以随时增加新的观察者 <a id="模式结构与角色"></a> ## 2. 模式结构与角色 ### 2.1 UML类图 ```plantuml @startuml class Subject { +attach(Observer) +detach(Observer) +notify() } class Observer { +update() } class ConcreteSubject { -subjectState +getState() +setState() } class ConcreteObserver { -observerState +update() } Subject <|-- ConcreteSubject Observer <|-- ConcreteObserver Subject o-- Observer ConcreteObserver --> ConcreteSubject @enduml
Subject(抽象主题)
ConcreteSubject(具体主题)
Observer(抽象观察者)
ConcreteObserver(具体观察者)
Java在java.util包中提供了Observable类和Observer接口的内置实现。
public class Observable { private boolean changed = false; private Vector<Observer> 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) { Object[] arrLocal; synchronized (this) { if (!changed) return; arrLocal = obs.toArray(); clearChanged(); } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); } protected synchronized void setChanged() { changed = true; } protected synchronized void clearChanged() { changed = false; } }
public interface Observer { void update(Observable o, Object arg); }
// 被观察者 class WeatherData extends Observable { private float temperature; public void measurementsChanged() { setChanged(); // 必须调用 notifyObservers(); } public void setMeasurements(float temperature) { this.temperature = temperature; measurementsChanged(); } } // 观察者 class CurrentConditionsDisplay implements Observer { @Override public void update(Observable o, Object arg) { if (o instanceof WeatherData) { WeatherData weatherData = (WeatherData)o; // 更新显示 } } } // 使用 WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay display = new CurrentConditionsDisplay(); weatherData.addObserver(display); weatherData.setMeasurements(80);
public interface Subject { void registerObserver(Observer o); void removeObserver(Observer o); void notifyObservers(); }
public interface Observer { void update(float temp, float humidity, float pressure); }
public class WeatherData implements Subject { private List<Observer> observers; private float temperature; private float humidity; private float pressure; public WeatherData() { observers = new ArrayList<>(); } @Override public void registerObserver(Observer o) { observers.add(o); } @Override public void removeObserver(Observer o) { observers.remove(o); } @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(); } }
在推模型中,Subject在通知Observer时,会将详细的数据通过参数传递给Observer。
public interface PushObserver { void update(float temp, float humidity, float pressure); } public class WeatherData implements Subject { // ... @Override public void notifyObservers() { for (Observer observer : observers) { observer.update(temperature, humidity, pressure); } } }
在拉模型中,Subject在通知Observer时,只传递最少的通知,Observer根据需要从Subject中拉取数据。
public interface PullObserver { void update(Subject subject); } public class WeatherData implements Subject { // ... @Override public void notifyObservers() { for (Observer observer : observers) { observer.update(this); } } public float getTemperature() { return temperature; } public float getHumidity() { return humidity; } public float getPressure() { return pressure; } }
特性 | 推模型 | 拉模型 |
---|---|---|
数据传递方式 | Subject主动推送所有数据 | Observer根据需要从Subject拉取数据 |
灵活性 | 较低,Subject决定传递哪些数据 | 较高,Observer决定需要哪些数据 |
耦合度 | 较高,Observer接口需包含所有参数 | 较低,只需Subject引用 |
性能 | 可能传递不必要的数据 | 只获取需要的数据 |
如前所述,Java提供了内置实现,但自Java 9已被标记为@Deprecated。
public class BeanExample { private PropertyChangeSupport support = new PropertyChangeSupport(this); public void addPropertyChangeListener(PropertyChangeListener pcl) { support.addPropertyChangeListener(pcl); } public void removePropertyChangeListener(PropertyChangeListener pcl) { support.removePropertyChangeListener(pcl); } private String value; public void setValue(String newValue) { String oldValue = this.value; this.value = newValue; support.firePropertyChange("value", oldValue, newValue); } }
button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // 处理按钮点击 } });
// 自定义事件 public class CustomEvent extends ApplicationEvent { public CustomEvent(Object source) { super(source); } } // 事件发布者 @Component public class EventPublisher { @Autowired private ApplicationEventPublisher publisher; public void publish() { publisher.publishEvent(new CustomEvent(this)); } } // 事件监听器 @Component public class EventListener { @EventListener public void handleCustomEvent(CustomEvent event) { // 处理事件 } }
Spring 4.2+提供了更灵活的事件监听方式:
@EventListener(condition = "#event.success") public void handleSuccessfulEvent(CustomEvent event) { // 条件监听 }
// Subject public class StockMarket { private Map<String, Double> prices = new HashMap<>(); private List<StockObserver> observers = new ArrayList<>(); public void addObserver(StockObserver observer) { observers.add(observer); } public void setPrice(String symbol, double price) { prices.put(symbol, price); notifyObservers(symbol, price); } private void notifyObservers(String symbol, double price) { for (StockObserver observer : observers) { observer.update(symbol, price); } } } // Observer public interface StockObserver { void update(String symbol, double price); } // Concrete Observer public class StockTrader implements StockObserver { private String name; public StockTrader(String name) { this.name = name; } @Override public void update(String symbol, double price) { System.out.printf("%s received update: %s is now %.2f\n", name, symbol, price); } } // 使用 StockMarket market = new StockMarket(); market.addObserver(new StockTrader("Trader1")); market.addObserver(new StockTrader("Trader2")); market.setPrice("AAPL", 150.25);
问题:多线程环境下Subject状态变更和通知可能不同步
解决方案: - 使用同步机制保护共享状态 - 考虑使用线程安全的集合类 - 使用CopyOnWriteArrayList存储观察者列表
public class ThreadSafeSubject implements Subject { private final List<Observer> observers = new CopyOnWriteArrayList<>(); @Override public void registerObserver(Observer o) { observers.add(o); } @Override public void notifyObservers() { for (Observer o : observers) { o.update(); } } }
问题:Observer未正确注销导致无法被垃圾回收
解决方案: - 提供明确的注销机制 - 使用WeakReference存储观察者 - 在适当生命周期点自动注销
public class WeakSubject implements Subject { private final List<WeakReference<Observer>> observers = new ArrayList<>(); @Override public void registerObserver(Observer o) { observers.add(new WeakReference<>(o)); } @Override public void notifyObservers() { Iterator<WeakReference<Observer>> it = observers.iterator(); while (it.hasNext()) { Observer o = it.next().get(); if (o != null) { o.update(); } else { it.remove(); // 清理已被GC的观察者 } } } }
public class EventBus { private final Map<Class<?>, List<Consumer<?>>> handlers = new ConcurrentHashMap<>(); public <T> void subscribe(Class<T> eventType, Consumer<T> handler) { handlers.computeIfAbsent(eventType, k -> new ArrayList<>()).add(handler); } public <T> void publish(T event) { List<Consumer<?>> eventHandlers = handlers.get(event.getClass()); if (eventHandlers != null) { for (Consumer<?> handler : eventHandlers) { ((Consumer<T>) handler).accept(event); } } } }
public class SimplePublisher implements Publisher<String> { private final ExecutorService executor = Executors.newFixedThreadPool(3); @Override public void subscribe(Subscriber<? super String> subscriber) { subscriber.onSubscribe(new Subscription() { @Override public void request(long n) { executor.submit(() -> { for (long i = 0; i < n; i++) { subscriber.onNext("Event " + i); } }); } @Override public void cancel() { // 处理取消逻辑 } }); } }
通知效率:大量Observer时,线性通知可能成为瓶颈
内存占用:每个Observer通常需要存储Subject引用
线程阻塞:同步通知可能导致调用链阻塞
事件风暴:频繁状态变化导致过多通知
观察者模式是Java中一种极其重要的设计模式,它通过定义对象间的一对多依赖关系,实现了松耦合的交互方式。从早期的AWT/Swing事件模型,到现代的Spring事件机制,观察者模式在Java生态中有着广泛的应用。
观察者模式虽然简单,但正确使用需要仔细考虑各种边界条件和性能影响。希望本文能帮助您全面理解并有效应用这一经典设计模式。 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。