首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 8 觀察者模式全解析:從經典實作到執行緒安全與非同步擴展

     編輯:Java 相關知識

觀察者模式(發布-訂閱)是 GUI、事件總線、反應式編程的基石。本文基於 Java 8 Stream API 與 Lambda,從經典 GoF 結構演進至專業化簡化版,深入剖析執行緒安全、有序通知、Mixin 復用、適配器模式、複雜/阻塞監聽器處理等實戰難題,附完整可運行代碼。

經典 vs 專業化結構對比

經典 GoF專業化簡化版
Subject/Observer 介面雙向依賴單向:Subject 持有 Listener 列表,Listener 只需實作單一方法
Observer 拉取狀態Subject 推送狀態物件給 Listener(參數化通知)
attach/detach 命名registerXXXListener / unregisterXXXListener

Java 8 核心實作

1. 領域模型

class Animal { private String name; /* getter/setter/建構子 */ }

2. 監聽器介面

@FunctionalInterface // 單一方法,支援 Lambda
interface AnimalAddedListener { void onAnimalAdded(Animal animal); }

3. 主題

class Zoo {
    private final List<Animal> animals = new ArrayList<>();
    private final List<AnimalAddedListener> listeners = new ArrayList<>();

    public void addAnimal(Animal a) {
        animals.add(a);
        notifyAnimalAddedListeners(a);
    }
    public AnimalAddedListener registerAnimalAddedListener(AnimalAddedListener l) {
        listeners.add(l); return l; // 回傳引用便於解除註冊
    }
    public void unregisterAnimalAddedListener(AnimalAddedListener l) {
        listeners.remove(l);
    }
    protected void notifyAnimalAddedListeners(Animal a) {
        listeners.forEach(l -> l.onAnimalAdded(a)); // Java 8 forEach + Lambda
    }
}

4. 客戶端使用

Zoo zoo = new Zoo();
// Lambda 註冊
AnimalAddedListener listener = zoo.registerAnimalAddedListener(
    a -> System.out.println("新增動物:" + a.getName()));
zoo.addAnimal(new Animal("老虎")); // 輸出:新增動物:老虎
zoo.unregisterAnimalAddedListener(listener);
zoo.addAnimal(new Animal("獅子")); // 無輸出

進階議題與解決方案

執行緒安全

  • 使用 ReentrantReadWriteLock:寫鎖保護註冊/解除,讀鎖保護通知遍歷。
  • 公平鎖 new ReentrantReadWriteLock(true) 保證 FIFO 順序,避免飢餓。

Mixin 復用主題邏輯

abstract class ObservableSubjectMixin<L> {
    private final List<L> listeners = new ArrayList<>();
    public L registerListener(L l) { listeners.add(l); return l; }
    public void unregisterListener(L l) { listeners.remove(l); }
    public void notifyListeners(Consumer<? super L> action) {
        listeners.forEach(action);
    }
}

class ZooUsingMixin extends ObservableSubjectMixin<AnimalAddedListener> {
    private final List<Animal> animals = new ArrayList<>();
    public void addAnimal(Animal a) {
        animals.add(a);
        notifyListeners(l -> l.onAnimalAdded(a));
    }
}

多事件類型:適配器模式

interface ZooListener {
    default void onAnimalAdded(Animal a) {}
    default void onAnimalRemoved(Animal a) {}
}
class ZooAdapter implements ZooListener {} // 空實作

class NamePrinter extends ZooAdapter {
    @Override public void onAnimalAdded(Animal a) {
        System.out.println("新增:" + a.getName());
    }
}

複雜/阻塞監聽器處理

  • 監聽器內部啟動新執行緒處理耗時邏輯,主線程立即返回。
  • 或主題通知時提交任務至專用 ExecutorService,實現生產者-消費者模式。
  • 需注意異常處理與生命週期管理(shutdown())。

命名規範速查表

監聽器介面:XxxListener / XxxEventListener
註冊方法:registerXxxListener(listener) → 回傳 listener
解除方法:unregisterXxxListener(listener)
通知方法:notifyXxxListeners(event)  // 複數 s 表示批量
事件物件:XxxEvent (單一狀態物件)

掌握這套模式,無論是 Swing 事件、Spring ApplicationEvent、RxJava、Kotlin Flow 皆可融會貫通。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved