觀察者模式 是 GoF 23 種設計模式中最經典的行為型模式之一,定義了對象間一對多的依賴關係。Java 8 引入 Lambda 表達式與函數式介面,為觀察者模式帶來了全新的實現方式。本文將從經典實現出發,逐步重構為現代 Java 8 風格,並探討線程安全、異步通知等進階主題。
update()// 主題介面
public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
// 觀察者介面
public interface Observer {
void update(String state);
}
// 具體主題
public class WeatherStation implements Subject {
private List<Observer> observers = new ArrayList<>();
private String weatherState;
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
observers.remove(o);
}
@Override
public void notifyObservers() {
for (Observer o : observers) {
o.update(weatherState);
}
}
public void setWeatherState(String state) {
this.weatherState = state;
notifyObservers();
}
}
// 具體觀察者
public class PhoneDisplay implements Observer {
@Override
public void update(String state) {
System.out.println("手機顯示天氣更新: " + state);
}
}
利用 @FunctionalInterface,單方法介面可直接用 Lambda 實例化:
@FunctionalInterface
public interface WeatherObserver {
void onWeatherChanged(String newState);
// 預設方法:支援組合
default WeatherObserver andThen(WeatherObserver other) {
return state -> {
this.onWeatherChanged(state);
other.onWeatherChanged(state);
};
}
}
public class WeatherStation {
// 使用 CopyOnWriteArrayList 保證線程安全
private final List<WeatherObserver> observers = new CopyOnWriteArrayList<>();
private String weatherState;
// 註冊返回註冊對象,支援後續移除
public WeatherObserver register(WeatherObserver observer) {
observers.add(observer);
return observer;
}
// 重載:支援 Lambda 直接註冊並返回引用
public WeatherObserver register(String id, WeatherObserver observer) {
// 可擴展:帶 ID 註冊,便於管理
return register(observer);
}
public boolean unregister(WeatherObserver observer) {
return observers.remove(observer);
}
public void setWeatherState(String state) {
this.weatherState = state;
notifyObservers(state);
}
// 核心通知邏輯:使用 forEach + 方法引用
private void notifyObservers(String state) {
observers.forEach(observer -> {
try {
observer.onWeatherChanged(state);
} catch (Exception e) {
// 隔離異常,不影響其他觀察者
System.err.println("觀察者通知失敗: " + e.getMessage());
}
});
}
}
public class Main {
public static void main(String[] args) {
WeatherStation station = new WeatherStation();
// 1. 傳統匿名內部類 (仍支援)
station.register(new WeatherObserver() {
@Override
public void onWeatherChanged(String state) {
System.out.println("【匿名類】天氣變化: " + state);
}
});
// 2. Lambda 表達式 (推薦)
WeatherObserver mobileObserver = state ->
System.out.println("【手機端】收到天氣: " + state);
station.register(mobileObserver);
// 3. 方法引用
station.register(System.out::println); // 直接打印
// 4. 組合觀察者 (Java 8 default 方法)
WeatherObserver combined = mobileObserver.andThen(state ->
System.out.println("【日誌記錄】" + state));
station.register("combined", combined);
// 觸發通知
station.setWeatherState("晴轉多雲,25°C");
// 移除特定觀察者
station.unregister(mobileObserver);
station.setWeatherState("驟雨,18°C");
}
}
public class WeatherEvent {
private final String state;
private final long timestamp;
private final String source;
public WeatherEvent(String state, String source) {
this.state = state;
this.timestamp = System.currentTimeMillis();
this.source = source;
}
// getter 省略
}
@FunctionalInterface
public interface EventObserver<T> {
void onEvent(T event);
}
public class EventSubject<T> {
private final List<EventObserver<T>> observers = new CopyOnWriteArrayList<>();
public void register(EventObserver<T> observer) {
observers.add(observer);
}
public void unregister(EventObserver<T> observer) {
observers.remove(observer);
}
public void fireEvent(T event) {
observers.forEach(obs -> {
try {
obs.onEvent(event);
} catch (Exception e) {
// 異常處理
}
});
}
}
| 容器 | 線程安全 | 適用場景 |
|---|---|---|
| ArrayList | 否 | 單線程、註冊/通知不併發 |
| CopyOnWriteArrayList | 是 (寫時複製) | 讀多寫少、觀察者數量較少 |
| Collections.synchronizedList | 是 (鎖同步) | 寫操作頻繁、需強一致性 |
| ConcurrentLinkedQueue | 是 (無鎖) | 高併發註冊/移除、允許弱一致性遍歷 |
observers.forEach(observer -> {
try {
observer.onEvent(event);
} catch (Exception e) {
// 記錄日誌,繼續通知下一個
log.error("Observer notification failed", e);
}
});
// 使用 CompletableFuture 異步通知
public void fireEventAsync(T event) {
observers.forEach(observer ->
CompletableFuture.runAsync(() -> {
try {
observer.onEvent(event);
} catch (Exception e) {
log.error("Async notification failed", e);
}
})
);
}
// 或使用固定線程池
private final ExecutorService executor = Executors.newFixedThreadPool(4);
public void fireEventAsyncPooled(T event) {
observers.forEach(observer ->
executor.submit(() -> {
try {
observer.onEvent(event);
} catch (Exception e) {
log.error("Pooled async notification failed", e);
}
})
);
}
遵循 Java 標準事件命名慣例:
*Listener 或 *Observer (如 ActionListener, WeatherObserver)add*Listener / register*Observerremove*Listener / unregister*Observerfire*Event / notify*Observerson*Event / *Changed (如 onWeatherChanged, actionPerformed)Java 8 通過 Lambda 表達式、函數式介面、預設方法、方法引用等特性,極大簡化了觀察者模式的實現:
default 方法支援觀察者鏈式組合CopyOnWriteArrayList 等並發容器開箱即用CompletableFuture 輕鬆實現非阻塞通知下篇將深入探討:反應式流 (Reactive Streams) 整合、背壓處理、分佈式觀察者模式、以及與 Spring ApplicationEvent、RxJava、Project Reactor 的對比整合。