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

Java 觀察者模式深度解析與標準實現

     編輯:Java 相關知識

模式定義與適用場景

觀察者模式定義對象間一對多依賴:當一個主題對象狀態變更,所有依賴它的觀察者自動收到通知並更新。典型場景:事件總線、GUI 監聽器、消息推送、緩存失效通知、數據同步觸發。

角色與接口設計

// 觀察者接口
public interface Observer {
    void update(Object event); // 事件載體可為任意類型
}

// 被觀察者(主題)接口
public interface Subject {
    void attach(Observer observer);
    void detach(Observer observer);
    void notifyObservers(Object event);
}

標準實現

具體主題

public class ConcreteSubject implements Subject {
    private final List<Observer> observers = new CopyOnWriteArrayList<>(); // 線程安全

    @Override
    public void attach(Observer observer) {
        if (observer != null) observers.add(observer);
    }

    @Override
    public void detach(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers(Object event) {
        for (Observer obs : observers) {
            try {
                obs.update(event);
            } catch (Exception e) {
                // 單個觀察者異常不影響其他
                log.error("Observer update failed", e);
            }
        }
    }

    // 業務方法觸發通知
    public void doBusinessLogic() {
        // ... 業務處理 ...
        notifyObservers(new BusinessEvent("ORDER_CREATED", orderId));
    }
}

具體觀察者

public class OrderNotificationObserver implements Observer {
    @Override
    public void update(Object event) {
        if (event instanceof BusinessEvent) {
            BusinessEvent be = (BusinessEvent) event;
            if ("ORDER_CREATED".equals(be.getType())) {
                // 發送郵件、推送、寫入消息隊列等
                notificationService.sendOrderCreated(be.getOrderId());
            }
        }
    }
}

測試驗證

public class ObserverPatternDemo {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        Observer obs1 = new OrderNotificationObserver();
        Observer obs2 = new InventoryUpdateObserver();
        Observer obs3 = new LoggingObserver();

        subject.attach(obs1);
        subject.attach(obs2);
        subject.attach(obs3);

        subject.doBusinessLogic(); // 觸發三個觀察者更新

        System.out.println("--- 移除 obs2 ---");
        subject.detach(obs2);
        subject.doBusinessLogic(); // 僅 obs1、obs3 響應
    }
}

輸出:

OrderNotificationObserver 收到: ORDER_CREATED #1001
InventoryUpdateObserver 收到: ORDER_CREATED #1001
LoggingObserver 收到: ORDER_CREATED #1001
--- 移除 obs2 ---
OrderNotificationObserver 收到: ORDER_CREATED #1002
LoggingObserver 收到: ORDER_CREATED #1002

進階變體與最佳實踐

1. 事件對象標準化

定義統一事件基類,攜帶類型、時間戳、來源、負載:

public class Event {
    private final String type;
    private final long timestamp = System.currentTimeMillis();
    private final Object source;
    private final Object payload;
    // getter...
}

2. 異步通知

使用 ExecutorService 或 CompletableFuture 解耦通知耗時:

public void notifyObserversAsync(Event event) {
    executor.submit(() -> notifyObservers(event));
}

3. 弱引用防內存洩漏

觀察者若未顯式 detach,主題強引用導致無法 GC。改用 WeakReference<Observer> 存儲,通知時過濾失效引用。

4. Spring 事件機制

生產環境推薦使用 ApplicationEventPublisher + @EventListener,框架級支持異步、排序、事務綁定。

JDK 內置支持

  • java.util.Observable / Observer(Java 9 棄用,線程不安全、類而非接口)
  • PropertyChangeSupport / PropertyChangeListener:JavaBeans 屬性變更通知標準
  • EventListener 模式:Swing/AWT 事件模型基礎

總結

觀察者模式實現「鬆耦合通知」,核心在於主題不關心觀察者具體實現。手寫版適合輕量級場景,企業級開發優先使用 Spring Events、Guava EventBus、RxJava 等成熟框架,獲得異步、重試、死信隊列等企業級能力。

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