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

Java 觀察者模式完整教程:從 JDK 內建到自定義實現

     編輯:Java 相關知識

觀察者模式核心思想

定義對象間一對多依賴,當主題狀態改變時,自動通知所有觀察者。核心在於鬆耦合:主題不關心觀察者如何處理,觀察者不關心主題內部細節。

關鍵角色

  • Subject(主題):維護觀察者列表,提供註冊/移除/通知介面。
  • Observer(觀察者):定義更新介面,接收通知後處理業務。

實現方案一:JDK 內建 Observable/Observer

// 主題繼承 Observable
public class UpdateObservable extends Observable {
    private int data;
    public void setData(int data) {
        if (data != this.data) {
            this.data = data;
            setChanged();      // 標記變更
            notifyObservers(); // 通知觀察者
        }
    }
    public int getData() { return data; }
}

// 觀察者實現 Observer 介面
public class UpdateObserver implements Observer {
    public void update(Observable o, Object arg) {
        if (o instanceof UpdateObservable) {
            System.out.println("收到數據變更:" + ((UpdateObservable)o).getData());
        }
    }
}

實現方案二:自定義觀察者模型(更靈活)

// 觀察者介面
public interface IWatcher {
    void update();
}

// 主題介面
public interface IWatchedSubject {
    void add(IWatcher w);
    void remove(IWatcher w);
    void notifyWatchers();
    void update(); // 業務變更觸發點
}

// 具體主題
public class UpdateWatchedSubject implements IWatchedSubject {
    private List watchers = new ArrayList<>();
    public void add(IWatcher w) { watchers.add(w); }
    public void remove(IWatcher w) { watchers.remove(w); }
    public void notifyWatchers() { watchers.forEach(IWatcher::update); }
    public void update() { System.out.println("主題更新中..."); notifyWatchers(); }
}

// 具體觀察者
public class UpdateWatcher implements IWatcher {
    public void update() { System.out.println(this + " 觀察到主題已更新"); }
}

變體:監聽器模式

監聽器是觀察者模式的特化形式,常用於事件驅動場景(如註冊、登入回調)。

public interface IRegisterListener { void onRegistered(); }
public interface ILoginListener { void onLogined(); }

public class User {
    public void register(IRegisterListener l) { 
        System.out.println("註冊中..."); l.onRegistered(); 
    }
    public void login(ILoginListener l) { 
        System.out.println("登入中..."); l.onLogined(); 
    }
}

實戰測試與輸出

public class Test {
    public static void main(String[] args) {
        // JDK 版
        new UpdateObservable(new UpdateObserver()).setData(99);
        
        // 自定義版
        IWatchedSubject s = new UpdateWatchedSubject();
        s.add(new UpdateWatcher()); s.add(new UpdateWatcher());
        s.update();
        
        // 監聽器版
        User u = new User();
        u.register(() -> System.out.println("監聽到註冊完成"));
        u.login(() -> System.out.println("監聽到登入完成"));
    }
}

輸出結果:

收到數據變更:99
主題更新中...
observer.UpdateWatcher@... 觀察到主題已更新
observer.UpdateWatcher@... 觀察到主題已更新
正在註冊中... 監聽到註冊完成
正在登入中... 監聽到登入完成

最佳實踐建議

  • 優先使用自定義介面,避免 JDK 版 Observable 類的限制(如非介面、同步鎖開銷)。
  • 考慮使用 java.util.concurrent.Flow (Java 9+) 實現響應式流觀察者模式。
  • 注意避免循環引用導致記憶體洩漏,適時移除觀察者。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved