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

Java 設計模式精講:觀察者模式(發布-訂閱)原理與實戰

     編輯:Java 相關知識

什麼是觀察者模式?

觀察者模式又稱發布-訂閱模式,定義物件間一對多依賴:當主題(Subject)狀態改變時,自動通知所有訂閱的觀察者(Observer)更新。核心價值在於解耦——主題與觀察者雙方都依賴抽象,而非具體實現。

生活場景類比

  • 米廠與商家:商家向米廠登記聯絡方式(註冊),米廠生產新米時通知所有商家來提貨
  • 書店缺貨登記:顧客登記想買的缺貨書,到貨時書店逐一電話通知
  • 回調函數:上層向底層註冊多個回調,條件滿足時底層調用回調

核心角色與關係

角色說明核心方法
Subject(抽象主題)管理觀察者列表,提供註冊/移除/通知attach, detach, notify
Observer(抽象觀察者)定義更新介面update()
ConcreteSubject具體主題,持有狀態getState, setState
ConcreteObserver具體觀察者,實作更新邏輯update() 內同步主題狀態

觀察者模式 UML 類圖

Java 完整實現

import java.util.ArrayList;
import java.util.List;

// 抽象主題
abstract class Subject {
    private List<Observer> observers = new ArrayList<>();

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

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

// 抽象觀察者
abstract class Observer {
    public abstract void update();
}

// 具體觀察者
class ConcreteObserver extends Observer {
    private String name;
    private String observerState;
    private ConcreteSubject subject;

    public ConcreteObserver(ConcreteSubject subject, String name) {
        this.subject = subject;
        this.name = name;
    }

    @Override
    public void update() {
        observerState = subject.getSubjectState();
        System.out.println(name + " 收到通知,狀態更新為:" + observerState);
    }
}

// 具體主題
class ConcreteSubject extends Subject {
    private String subjectState;

    public String getSubjectState() { return subjectState; }
    public void setSubjectState(String subjectState) {
        this.subjectState = subjectState;
        System.out.println("主題狀態變更為:" + subjectState);
    }

    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        subject.attach(new ConcreteObserver(subject, "觀察者X"));
        subject.attach(new ConcreteObserver(subject, "觀察者Y"));
        subject.attach(new ConcreteObserver(subject, "觀察者Z"));

        subject.setSubjectState("Ready");
        subject.notifyObservers();
    }
}

執行輸出

主題狀態變更為:Ready
觀察者X 收到通知,狀態更新為:Ready
觀察者Y 收到通知,狀態更新為:Ready
觀察者Z 收到通知,狀態更新為:Ready

C++ 實現的額外考量

C++ 需手動管理記憶體:

  • Subject 持有 Observer* 指標
  • Observer 銷毀前必須呼叫 detach,否則 Subject 仍持有野指標,下次 notify 導致 crash
  • 可考慮讓 Subject 管理 Observer 生命週期(智慧指標)

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

Java 9 起標記 @Deprecated,原因:

  • Observable 是類而非介面,限制繼承
  • 通知順序固定,不可自訂
  • 非線程安全

現代替代方案:

  • JavaBeans PropertyChangeListener
  • Guava EventBus / Spring ApplicationEvent
  • RxJava / Reactor 反應式流
  • 自訂介面 + CopyOnWriteArrayList 保證線程安全

模式優缺點總結

優點缺點
主題與觀察者鬆耦合觀察者過多時通知延遲
支援廣播通訊循環依賴導致死循環風險
符合開閉原則若觀察者更新耗時,阻塞主題

適用場景檢查清單

  • [ ] 一個物件狀態變更需通知多個物件
  • [ ] 通知對象動態變化(運行時增減)
  • [ ] 主題不需知道觀察者具體類別
  • [ ] 需跨層級通訊(如 UI 層監聽資料層變化)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved