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

Java 觀察者模式完整實戰:自定義實現、JDK 內置、Spring 事件、RxJava 響應式對比

     編輯:Java 相關知識

模式定義

定義對象間一對多依賴,當一個對象(Subject)狀態變化,所有依賴者(Observer)自動收到通知並更新。

自定義實現(教學級)

核心接口


public interface Subject {
    void register(Observer o);
    void unregister(Observer o);
    void notifyObservers();
    Object getUpdate(Observer o);
}

public interface Observer {
    void update();
    void setSubject(Subject s);
}

主題實現


public class Topic implements Subject {
    private final List observers = new CopyOnWriteArrayList<>();
    private String message;
    private final Object lock = new Object();

    @Override public void register(Observer o) {
        if (o == null) throw new NullPointerException();
        observers.addIfAbsent(o);
    }
    @Override public void unregister(Observer o) { observers.remove(o); }

    @Override public void notifyObservers() {
        List snapshot;
        synchronized (lock) {
            if (message == null) return; // 無更新
            snapshot = new ArrayList<>(observers);
        }
        snapshot.forEach(Observer::update); // 無鎖通知
    }

    @Override public Object getUpdate(Observer o) { return message; }

    public void post(String msg) {
        synchronized (lock) {
            this.message = msg;
        }
        notifyObservers();
    }
}

觀察者實現


public class Subscriber implements Observer {
    private final String name;
    private Subject topic;

    public Subscriber(String name) { this.name = name; }

    @Override public void update() {
        String msg = (String) topic.getUpdate(this);
        System.out.println(name + (msg == null ? ":: 無新消息" : ":: 收到 → " + msg));
    }
    @Override public void setSubject(Subject s) { this.topic = s; }
}

測試


public class Demo {
    public static void main(String[] args) {
        Topic topic = new Topic();
        Observer o1 = new Subscriber("觀察者-1");
        Observer o2 = new Subscriber("觀察者-2");
        topic.register(o1); topic.register(o2);
        o1.setSubject(topic); o2.setSubject(topic);

        topic.post("第一條消息");
        topic.post("第二條消息");
    }
}

JDK 內置 java.util.Observable / Observer(已棄用)

  • Java 9 標註 @Deprecated(since="9")
  • 缺點:Observable 是類而非接口,單繼承限制;setChanged() 受保護,需繼承才能用
  • 不推薦新項目使用

Spring ApplicationEvent —— 企業級標準


// 1. 定義事件
public class OrderCreatedEvent extends ApplicationEvent {
    private final Long orderId;
    public OrderCreatedEvent(Object source, Long orderId) { super(source); this.orderId = orderId; }
    public Long getOrderId() { return orderId; }
}

// 2. 發布
@Component
public class OrderService {
    @Autowired ApplicationEventPublisher publisher;
    public void create() {
        Long id = 100L;
        publisher.publishEvent(new OrderCreatedEvent(this, id));
    }
}

// 3. 監聽
@Component
public class InventoryListener {
    @EventListener
    public void handle(OrderCreatedEvent event) {
        System.out.println("庫存扣減:訂單 " + event.getOrderId());
    }
    @EventListener(condition = "#event.orderId > 1000")
    public void handleBig(OrderCreatedEvent event) { /* 大單特殊處理 */ }
}

// 4. 異步
@EnableAsync
@EventListener @Async
public void asyncHandle(OrderCreatedEvent event) { ... }

優勢:解耦、支持異步、SpEL 條件過濾、有序 @Order、事務綁定 @TransactionalEventListener。

RxJava 響應式觀察者


PublishSubject subject = PublishSubject.create();

// 訂閱者 1
subject.subscribe(msg -> System.out.println("訂閱者1: " + msg));

// 訂閱者 2(僅接收含 "error" 的消息)
subject.filter(msg -> msg.contains("error"))
       .subscribe(msg -> System.out.println("錯誤流: " + msg));

// 發布
subject.onNext("正常日誌");
subject.onNext("error: 連接超時");
subject.onComplete();

優勢:操作符豐富、背壓支持、線程調度、組合變換。

選型決策表

場景推薦方案
簡單解耦、無框架依賴自定義接口 / Guava EventBus
Spring Boot 微服務內部事件Spring ApplicationEvent
跨服務異步解耦消息隊列 + 領域事件
複雜流處理、背壓、合流分流RxJava / Reactor / Flow API
UI 綁定、Android LiveDataLifecycle-aware Observable

避坑指南

  • ❌ 通知時持有鎖 → 死鎖風險 → 快照模式 + 無鎖通知
  • ❌ 觀察者內部耗時操作阻塞發布者 → 異步執行 / 線程池
  • ❌ 循環引用導致內存洩漏 → WeakReference / 及時 unregister
  • ❌ 事件風暴 → 合併事件 / 節流 / 防抖
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved