JavaScript設計モード(六):観察者モードと発表購読モード


観察者モード(Observer)
観察者モード:オブジェクト間の1対以上の依存関係を定義し、対象となるSubjectの状態が変化した場合、すべての依存するオブジェクトObserverが通知されます.
簡単に点をつけます:女神は彼氏がいて、友達は囲んで図を日に当てて、幸せな宣言“おばあさんは成功して単に脱いで、あなた達が喜ぶことを望みます”.皆さんが隠していた予備の失恋は、自分を慰めるしかないです.
パターンの特徴
  • オブジェクトSubjectは、方法を有している.
  • 以上の観察者オブジェクトObserverは、Observerの状態変更通知を受信し、処理する方法を有する.
  • ターゲットSubjectの状態変更の場合は、全Subjectに通知する.
  • Observerは、一連のSubjectを追加し、Observerは、これらSubjectとの間の連絡を維持する責任があります.
    コードの実装
    //     
    class Subject {
      constructor() {
        this.observers = [];  //      
      }
      //   
      add(observer) {
        this.observers.push(observer);
      }
      //   
      remove(observer) {
        let idx = this.observers.findIndex(item => item === observer);
        idx > -1 && this.observers.splice(idx, 1);
      }
      //   
      notify() {
        for (let observer of this.observers) {
          observer.update();
        }
      }
    }
    
    //     
    class Observer {
      constructor(name) {
        this.name = name;
      }
      //             
      update() {
        console.log(`         ,  :${this.name}`);
      }
    }
    
    //       
    let subject = new Subject();
    
    //         
    let obs1 = new Observer('     ');
    let obs2 = new Observer('     ');
    
    //          
    subject.add(obs1);
    subject.add(obs2);
    
    //        
    subject.notify();  
    //   :
    //          ,       
    //          ,       
    優勢
  • ターゲットと観察者、機能結合度が低下し、自身の機能論理に集中する.
  • 観察者は、更新を受動的に受信し、時間的に結合し、リアルタイムに受信対象者の更新状態を受信する.
  • 不完全です
    観察者モードは、オブジェクト間の依存関係の低結合を実現しているが、イベント通知を「スクリーニング通知」「件名イベント通知を指定する」など、細分化して制御することはできない.
    例えば、上記の例では、「先端開発者」のみを通知しますか?観察者の対象はどうやって自分の必要な更新通知だけを受信しますか?上記の例では、2つの観察者は、対象者の状態変更通知を受信した後、Observerを実行し、区別がない.
    「00後は個性を追い求める時代ですが、ちょっと違っていますか?」ということが、次のパターンを引き出してくれます.階段版の観察者モード.「購読モードの発表」は、一部の文章では両者が同じかどうかについて議論があります.
    個人の観点だけを表します.二つのモードは似ていますが、やはり少し違っています.JavaScriptは非正規的に対象言語に向かっています.また、関数はプログラムの特徴を調整して、JavaScriptのコード実現は「観察モード」に相当します.
    購読モード(Publisher&Subscriber)をリリースします.
    購読モードをリリースします.イベント(件名)チャネルに基づいて、通知を受信したい対象のSubscriberは、イベントをカスタマイズしてテーマを購読し、アクティブ化されたオブジェクトPublisherは、テーマイベントをリリースすることによって、各購読対象のSubscriberに通知します.
    購読モードのリリースは観察者モードとは異なり、イベントセンターには「第三者」が登場します.対象者は観察者に直接通知するのではなく、イベントセンターを通じて通知を送る.
    コードの実装
    //     
    let pubSub = {
      list: {},
      subscribe: function (key, fn) {   //   
        if (!this.list[key]) {
          this.list[key] = [];
        }
        this.list[key].push(fn);
      },
      publish: function(key, ...arg) {  //   
        for(let fn of this.list[key]) {
          fn.call(this, ...arg);
        }
      },
      unSubscribe: function (key, fn) {     //     
        let fnList = this.list[key];
        if (!fnList) return false;
    
        if (!fn) {
          //             ,     key    
          fnList && (fnList.length = 0);
        } else {
          fnList.forEach((item, index) => {
            if (item === fn) {
              fnList.splice(index, 1);
            }
          })
        }
      }
    }
    
    //   
    pubSub.subscribe('onwork', time => {
      console.log(`   :${time}`);
    })
    pubSub.subscribe('offwork', time => {
      console.log(`   :${time}`);
    })
    pubSub.subscribe('launch', time => {
      console.log(`   :${time}`);
    })
    
    //   
    pubSub.publish('offwork', '18:00:00'); 
    pubSub.publish('launch', '12:00:00');
    
    //     
    pubSub.unSubscribe('onwork');
    購読モードをリリースする場合、購読者はそれぞれ異なる論理を実現し、自分の対応するイベント通知のみを受信する.あなたが望む「違い」を実現します.
    DOMイベントの傍受も「購読モードのリリース」のアプリケーションです.
    let loginBtn = document.getElementById('#loginBtn');
    
    //       (    )
    function notifyClick() {
        console.log('     ');
    }
    
    //       
    loginBtn.addEventListener('click', notifyClick);
    //     ,           
    loginBtn.click();             
    
    //       
    loginBtn.removeEventListener('click', notifyClick);
    購読通知の順序を発表します.
  • 購読してからリリースする時に通知します.
  • 購読後、過去のリリース通知(QQオフラインメッセージ、オンラインで前の情報を取得)
  • を取得することができます.
    流行庫の応用
  • jQueryのupdate()ontriggerと、$.callback()と、
  • Vueの双方向データバインディング.
  • Vueの親子コンポーネント通信$on/$emit
  • jQueryの$Callback()
    jQueryの$Callback()は観察者モードの応用のようで、より細かい粒度制御ができません.
    function notifyHim(value) {
     console.log('He say ' + value);
    }
    
    function notifyHer(value) {
     console.log('She say ' + value);
    }
    
    $cb = $.Callbacks();    //         :     
    
    $cb.add(notifyHim);     //          :  
    $cb.add(notifyHer);     //          :  
    
    $cb.fire('help');       //       :   
    Vueの双方向データバインディングObject.defineProperty()を用いてデータをハイジャックし、データオブジェクトの属性を傍受するためのモニターObserverを設け、属性に変化があれば、購読者Depに通知してデータを更新し、最後に対応するコマンドを解析して、対応する更新関数を実行してビューを更新する.双方向バインディングを実現しました.
  • Watcher(データハイジャック)
  • Compile(購読発表)
  • Observer(データ傍受)
  • Dep(アナログコンパイル)
  • Vue双方向データバインディングの原理については、自分で他の記事を参照するか、またはこの「vue双方向データバインディングの原理」を紹介します.
  • Vueソース転送ゲート
  • Vueの親子コンポーネント通信Watcherにおいて、親コンポーネントは、Compileを介して、データ(上から下への一方向のデータストリーム)をサブアセンブリに渡す.親子構成要素間の通信は、カスタムイベントすなわちVuepropsによって実現される(サブアセンブリ$on、親構成要素$emit).
    原理は、$emitが更新通知を発行し、$onが購読通知を受信することである.$emitには、$on(1回の傍受)、Vue(購読中止)が実装されている.
    //   
    vm.$on('test', function (msg) {
        console.log(msg)
    })
    
    //   
    vm.$emit('test', 'hi')
  • Vueソース転送ゲート
  • Vue文書転送ゲート
  • 優勢
  • オブジェクト間機能の結合、弱体化オブジェクト間の参照関係、
  • より細かく管理し、指定購読テーマ通知を配信する.
    不完全です
  • ペア間の結合後、コードの読み取りは直感的ではなく、維持しにくいです.
  • 追加オブジェクト作成、消費時間とメモリ(多くの設計モードの共通病気)
  • 観察者モードVS購読モードのリリース
    類似点
    一つのペアの依存関係を定義し、状態が変更された時に対応する通知を実行します.
    違い点
    購読モードをより柔軟にリリースすることは、進行版の観察者モードであり、配信に対応することを指定する.
  • 観察者モードは、単一のイベントに対応する複数のイベントに依存するオブジェクト関係を維持し、
  • 購読・維持する複数のイベント(件名)と各イベント(件名)に依存するオブジェクトとの関係を発表する
  • .
  • 観察者モードは、対象物が直接トリガ通知(全通知)であり、観察対象は通知を受信することを余儀なくされている.発表購読モードが複数ある中間層(イベントセンター)は、通知放送を管理する(対応イベントの購読対象のみを通知する).
  • 観察者はモードオブジェクト間の依存関係が強く、発行購読モードにおけるオブジェクト間の真のデカップリングが実現される.
  • オブジェクト属性データブロック方式:
  • $once属性記述子、
  • ES 6クラスset;
  • ES 6 $offエージェント、
  • 参考記事:
  • 観察者モードと購読モードのリリースについて話す
  • 元JavaScript観察者モードを実現する
  • 観察者モードvsが購読モード
  • をリリースする.
  • vue双方向データバインディング原理
  • 本記事の第1弾Githubは、Starを期待しています.https://github.com/ZengLingYong/blog
    作者:以楽之名
    この文章はオリジナルで、不適切なところがあります.転載は出典を教えてください.