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

觀察者模式深度解析:經典實現、抽象主題重構與 Java 內置支援

     編輯:Java 程式設計入門

模式定義與角色

觀察者模式:定義對象間一對多依賴,當一個對象 (主題/Subject) 狀態改變,所有依賴它的對象 (觀察者/Observer) 都得到通知並自動更新。屬於行為型模式。

四大核心角色

  1. Subject (抽象主題):定義註冊/移除/通知觀察者接口。
  2. ConcreteSubject (具體主題):持有狀態,狀態變化時調用通知。
  3. Observer (抽象觀察者):定義 update() 接口。
  4. ConcreteObserver (具體觀察者):實現更新邏輯,可持有對主題引用以獲取詳情。

版本一:接口版 — 輕量、標準

// 抽象主題
public interface Subject {
    void attach(Observer o);
    void detach(Observer o);
    void notifyObservers();
}

// 具體主題
public class ConcreteSubject implements Subject {
    private List observers = new ArrayList<>();
    private String state; // 業務狀態

    public void attach(Observer o) { observers.add(o); }
    public void detach(Observer o) { observers.remove(o); }

    public void notifyObservers() {
        for (Observer o : observers) o.update(); // 或 o.update(this, state)
    }

    // 業務方法修改狀態後通知
    public void setState(String state) {
        this.state = state;
        notifyObservers();
    }
}

// 抽象觀察者
public interface Observer {
    void update(); // 或 update(Subject s, Object arg)
}

// 具體觀察者
public class ConcreteObserver implements Observer {
    private String name;
    public ConcreteObserver(String name) { this.name = name; }
    public void update() { System.out.println(name + " notified, state changed"); }
}

// 客戶端
public static void main(String[] args) {
    Subject subject = new ConcreteSubject();
    subject.attach(new ConcreteObserver("Observer1"));
    subject.attach(new ConcreteObserver("Observer2"));
    subject.setState("NEW_STATE"); // 觸發通知
}

版本二:抽象類重構 — 模板方法消除重複

將觀察者集合管理、通知邏輯上移至抽象類 Subject,具體主題僅關注業務狀態變化:

public abstract class Subject {
    private List observers = new ArrayList<>();

    public void attach(Observer o) { observers.add(o); }
    public void detach(Observer o) { observers.remove(o); }

    public void notifyObservers() {
        for (Observer o : observers) o.update();
    }

    // 模板方法:子類實現具體狀態變更,父類負責通知
    public abstract void change(String newState);
}

public class ConcreteSubject extends Subject {
    private String state;
    @Override
    public void change(String newState) {
        this.state = newState;
        notifyObservers(); // 狀態變更後自動通知
    }
}
// Observer/ConcreteObserver 不變

優勢:遵循「好萊塢原則」——「別調用我們,我們會調用你」;具體主題無需關心通知機制,專注業務邏輯。

Java 內置支援:java.util.Observable / Observer (已棄用)

public class WeatherData extends Observable {
    private float temperature;
    public void setTemperature(float t) {
        this.temperature = t;
        setChanged(); // 關鍵:標記狀態已變
        notifyObservers(temperature); // 推模式:傳遞數據
    }
}

public class CurrentDisplay implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        float temp = (Float) arg;
        System.out.println("Current temp: " + temp);
    }
}
// 註:Java 9 標記 @Deprecated(since="9"),因設計缺陷 (Observable 是類而非接口、notifyObservers 同步、無泛型)

現代最佳實踐:事件總線 / Reactive Streams

設計決策清單

  1. 推 vs 拉:notifyObservers(data) 推模式數據即時但耦合;notifyObservers() 觀察者自行 subject.getState() 拉模式解耦但可能讀舊值。
  2. 同步 vs 異步:同步阻塞主題線程;異步需線程池、異常隔離、順序保證。
  3. 生命週期管理:誰註冊誰移除?防止內存洩漏 (觀察者持有主題引用阻礙 GC)。
  4. 遞歸通知防護:觀察者 update 中修改主題狀態 → 死循環,需 setChanged() 守衛或異步隊列緩衝。

一句話精髓

public class Subject { public void notify() { observers.forEach(Observer::update); } } — 核心就是「持有列表、遍歷調用」,其餘皆為工程化包裝。

掌握觀察者模式,是理解事件驅動架構、響應式編程、微服務異步通信的基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方案特點適用場景
Guava EventBus註解驅動 (@Subscribe)、同步/異步、死事件檢測模組解耦、插件系統、Android 事件分發
Spring ApplicationEvent容器集成、事務綁定 (@TransactionalEventListener)、異步 @AsyncSpring 生態業務事件、領域事件發布
RxJava / Reactor響應式流、背壓、操作符豐富 (map/filter/flatMap)高吞吐異步管道、實時數據流、移動端響應式 UI
Kafka / RocketMQ分布式、持久化、重放、順序保證微服務異步通信、事件溯源、日誌聚合