觀察者模式的項目實踐

業(yè)務場景

項目是一個單頁面web應用,有一個基礎(chǔ)的websocket服務,用于和服務器通信。剛開始主要有兩個作用:

  1. 賬號防重復登陸。當賬號在另外的地方登陸時,websocket收到服務器消息,網(wǎng)站即時彈窗提示用戶“當前賬號在另外一個地方登陸”,然后網(wǎng)站清除登錄信息并跳轉(zhuǎn)到登錄頁面。
  2. 當打開送貨管理界面時,若有新的送貨請求,websocket收到服務器消息,即時提示用戶“您有新的送貨請求,請及時處理”。若沒有打開送貨管理界面,不提示。

起初是這樣的實現(xiàn)的:

//BasciWebsocket.js
 websocket.onmessage = function (event) {
   try{
        let {data} = event;
        let _data = JSON.parse(data);
        switch(_data.type){
          case 100:
            Modal.warning({
              title: '賬號登錄提醒',
              content: "您的賬號已經(jīng)在另外的地方進行登陸,請確認是否您本人操作。如有異常,請聯(lián)系公司系統(tǒng)管理員。",
              okText: '知道了',
              onOk: ()=> {
                tool.clearUserCookie();
                window.location = "/login";
              }
            });
            break;
          case 101:
            let isPageShow = tool.ifDeliveryPageShow();
            if(isPageShow){
               //提示“您有新的送貨請求,請及時處理”
            }
            break;
        }
      }catch(e){

      }
 };

看起來并沒有什么問題。但是,隨著項目越來越復雜,websocket負責通知的消息也越來越豐富。接收到消息后,往往還要改變具體的頁面展現(xiàn),跟具體的頁面的關(guān)聯(lián)性非常大。比如,用戶停留在訂單詳情頁時,如果收到新的訂單反饋,那么訂單詳情頁的評論列表區(qū)域就要動畫出現(xiàn)新的反饋信息。

這個時候,你會發(fā)現(xiàn),把這類跟具體頁面強關(guān)聯(lián)的邏輯寫在基礎(chǔ)的BasciWebsocket.js文件里不科學,BasciWebsocket.js也變得很臃腫,維護起來有些費勁。問題就在于基礎(chǔ)的websocket服務與每個頁面的消息處理邏輯不夠解耦。

不難看出,在這個業(yè)務場景里,websocket服務其實就是一個消息發(fā)布者,而這些具體頁面則是消息訂閱者。很自然地,我想到了一根救命稻草——經(jīng)典的發(fā)布-訂閱模式(又叫觀察者模式)。

觀察者模式

觀察者模式定義對象間的一種一對多的依賴關(guān)系,當一個對象的狀態(tài)發(fā)生改變時,所有依賴它的對象都將得到通知。

如何實現(xiàn)觀察者模式?

  1. 指定好誰充當發(fā)布者(websocket服務);
  2. 為發(fā)布者添加一個緩存列表,用于存放回調(diào)函數(shù)以便通知訂閱者(具體頁面);
  3. 發(fā)布者對外提供消息訂閱/退訂方法,實質(zhì)就是改變緩存列表的內(nèi)容;
  4. 發(fā)布消息時,發(fā)布者會遍歷這個緩存列表,一次觸發(fā)里面存放的訂閱者回調(diào)函數(shù);

實踐

首先,把BasciWebsocket.js變身為消息發(fā)布者:

export default class BasicWebsocket{

  constructor() {
    if(typeof BasicWebsocket.instance === 'object') {
      return BasicWebsocket.instance;
    }
    //緩存列表
    this.listeners = {};
    this.init();
    
    BasicWebsocket.instance = this;
  }

  //消息訂閱
  addListener = (key,func)=>{
     this.listeners[key] = func;
  };

  //取消訂閱
  removeListener = (key)=>{
     delete this.listeners[key];
  };


  init = ()=>{
    //獲取websocket對象,全局唯一
    let websocket = this.getWebsocket(); 

    let that = this;
    //監(jiān)聽websocket消息
    websocket.onmessage = function (event) {
      try{
        let {data} = event
        let _data = JSON.parse(data);
        //遍歷緩存列表, 通知消息訂閱者
        let keys = Object.keys(that.listeners);
        for(let i = 0,j = keys.length; i < j; i++){
          let func = that.listeners[keys[i]];
          func(_data);
        }
      }catch(e){

      }
    };
  };
  
  //其他代碼
}

然后,在發(fā)貨管理頁加載時,可以進行發(fā)貨消息的訂閱;發(fā)貨管理頁卸載時,進行消息退訂。其他頁面如此類推。

class Distribution extends Component{
  // 構(gòu)造
  constructor(props) {
    super(props);
    // 初始狀態(tài)
    this.state = {
      newCount:0
    };
    this.websocket = new BasicWebsocket();
  }

  //組件加載完畢
  componentDidMount() {
    let that = this; 
    //消息訂閱
    this.websocket.addListener("distribution",(d)=>{
      if(d.type == 101){
        that.showNotification(); //提示“您有新的送貨請求,請及時處理”
        //在頁面展示新的發(fā)貨請求數(shù)量
        let {count} = d.data;
        let count = that.state.newCount + count;
        that.setState({
          newCount:count
        });
      }
    });
  }

  //組件即將卸載
  componentWillUnmount() {
    //消息退訂
    this.websocket.removeListener("distribution");
  }
}

至此,通過觀察者模式實現(xiàn)了基礎(chǔ)websocket服務和具體頁面邏輯的解耦,代碼可維護性得到提高。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,048評論 25 709
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,564評論 19 139
  • 點擊查看原文 Web SDK 開發(fā)手冊 SDK 概述 網(wǎng)易云信 SDK 為 Web 應用提供一個完善的 IM 系統(tǒng)...
    layjoy閱讀 14,314評論 0 15
  • 工廠模式類似于現(xiàn)實生活中的工廠可以產(chǎn)生大量相似的商品,去做同樣的事情,實現(xiàn)同樣的效果;這時候需要使用工廠模式。簡單...
    舟漁行舟閱讀 8,130評論 2 17
  • 今天的閱讀材料是《零秒思考》,讀了兩遍才讀真正讀懂。 第一遍看的時候,印象最深的就是拿一張A4紙,橫放,寫標題,寫...
    烏卓閱讀 498評論 1 5

友情鏈接更多精彩內(nèi)容