Java里觀察者模式(訂閱發布模式)


在公司開發項目,如果碰到一些在特定條件下觸發某些邏輯操作的功能的實現基本上都是用的定時器

比如用戶注冊完后,發送郵件,為了防止郵件發送失敗或者發送郵件比較耗時,一般也都是通過定時器去掃庫里注冊沒有發郵件的用戶數據

再比如一個訂單,在改變狀態后,要歸檔,這也是通過定時器來實現的,掃描訂單的數據,通過判斷狀態來做相對應的處理

但這樣處理的話,定時器就會越來越多,總覺得不太好

然后,從一些資訊網站上的訂閱功能想到了是否可以使用java里的觀察者模式來解決這個問題,比如定單的狀態改變了,這是一個主題,直接通知訂閱這個主題的實現類來處理這個訂單,這樣不是更方便嗎,於是從觀察者模式入手,折騰了一下

創建主題(Subject)接口

定義主題的接口

package co.yiiu;

/** * Created by tomoya at 2019/4/8 */
public interface Subject {

  // 設置主題內容
  void setContent(String content);

  // 獲取主題內容
  String getContent();

  // 添加訂閱者
  void attach(Observer observer);

  // 刪除訂閱者
  void detach(Observer observer);

  // 發布消息
  void publish();
}

創建訂閱者(Observer)接口

package co.yiiu;

/** * Created by tomoya at 2019/4/8 */
public interface Observer {

  // 訂閱主題
  void subscribe(Subject subject);

  // 取消訂閱
  void unsubscribe(Subject subject);

  // 處理訂閱的消息
  void update(Subject subject);
}

原鏈文接:https://tomoya92.github.io/2019/04/08/java-subscribe-publish/

實現主題

我這里實現了兩個主題

  • NewsSubject 新聞主題,訂閱了這個主題的觀察者可以獲取這個主題更新的新聞內容
  • WeatherSubject 天氣主題,訂閱了這個主題的觀察者可以獲取這個主題發布的天氣情況

具體代碼如下

package co.yiiu;

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

/** * Created by tomoya at 2019/4/8 */
public class NewsSubject implements Subject {

  private String content;
  private List<Observer> observers = new ArrayList<>();

  @Override
  public String getContent() {
    return content;
  }

  @Override
  public void setContent(String content) {
    this.content = content;
  }

  // 添加觀察者
  @Override
  public void attach(Observer observer) {
    observers.add(observer);
  }

  // 刪除觀察者
  @Override
  public void detach(Observer observer) {
    observers.remove(observer);
  }

  // 通知觀察者
  @Override
  public void publish() {
    observers.forEach(observer -> observer.update(this));
  }
}
package co.yiiu;

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

/** * Created by tomoya at 2019/4/8 */
public class WeatherSubject implements Subject {

  private String content;
  private List<Observer> observers = new ArrayList<>();

  @Override
  public String getContent() {
    return content;
  }

  @Override
  public void setContent(String content) {
    this.content = co 大專欄  Java里觀察者模式(訂閱發布模式)ntent;
  }

  @Override
  public void attach(Observer observer) {
    observers.add(observer);
  }

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

  @Override
  public void publish() {
    observers.forEach(observer -> observer.update(this));
  }
}

文原鏈接:https://tomoya92.github.io/2019/04/08/java-subscribe-publish/

實現觀察者

我這寫了一個通用的實現,創建觀察者的時候,傳遞一個名字表示不同的觀察者

package co.yiiu;

/** * Created by tomoya at 2019/4/8 */
public class ConcreteObserver implements Observer {

  private String name;

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

  @Override
  public void subscribe(Subject subject) {
    subject.attach(this);
  }

  @Override
  public void unsubscribe(Subject subject) {
    subject.detach(this);
  }

  @Override
  public void update(Subject subject) {
    System.out.println(this.name + " 訂閱的內容: " + subject.getContent());
  }
}

測試

package co.yiiu;

import org.junit.Test;

/** * Created by tomoya at 2019/4/8 */
public class TestObserver {


  @Test
  public void test() {
    // 創建主題對象
    Subject newsSubject = new NewsSubject();
    Subject weatherSubject = new WeatherSubject();

    // 給主題賦值
    newsSubject.setContent("我是一條新聞消息");
    weatherSubject.setContent("我是一條天氣消息");

    // 創建訂閱者
    Observer concreteObserver1 = new ConcreteObserver("用戶1");
    // 訂閱newsSubject
    concreteObserver1.subscribe(newsSubject);

    Observer concreteObserver2 = new ConcreteObserver("用戶2");
    // 訂閱newsSubject和weatherSubject
    concreteObserver2.subscribe(newsSubject);
    concreteObserver2.subscribe(weatherSubject);

    Observer concreteObserver3 = new ConcreteObserver("用戶3");
    // 訂閱weatherSubject
    concreteObserver3.subscribe(newsSubject);
    concreteObserver3.subscribe(weatherSubject);

    // user2 取消訂閱newsSubject
    concreteObserver2.unsubscribe(newsSubject);

    // 發布消息
    newsSubject.publish();
    weatherSubject.publish();

  }
}

運行結果

用戶1 訂閱的內容: 我是一條新聞消息
用戶3 訂閱的內容: 我是一條新聞消息
用戶2 訂閱的內容: 我是一條天氣消息
用戶3 訂閱的內容: 我是一條天氣消息

總結

有了這個訂閱發布模式了,就可以解決類似訂單狀態改變后的處理邏輯了

  1. 創建一個訂單主題
  2. 創建一個觀察者來訂閱這個訂單主題
  3. 當訂單狀態有變化時,通過訂單主題發布這個訂單
  4. 這時候只要訂閱了這個訂單主題的觀察者就能收到消息,然后就可以處理這個狀態有變化的訂單了

java.util 包里也有 Observable Observer

不過它是通過被觀察者主動添加觀察者來實現的,當有消息了,調用 notifyObservers() 方法來通知觀察者

這種做法還需要被觀察者去維護觀察者,不太好,還不如讓觀察者主動去訂閱干脆

寫博客不易,轉載請保留原文鏈接,謝謝!

原文鏈接: https://tomoya92.github.io/2019/04/08/java-subscribe-publish/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM