JavaScript設計モードの配布-購読モード(オブザーバーモード)-part 1


『JavaScriptデザインモデルと開発実践』読書ノート.
パブリッシュ-サブスクリプションモードは、オブジェクト間の1対多の依存関係を定義するオブザーバモードとも呼ばれます.1つのオブジェクトのステータスが変更されると、依存するすべてのオブジェクトが通知されます.
たとえば、segmentfaultでは、ある問題に注目しています.このとき、この問題のメッセージを購読したと言えるでしょう.この質問に新しい回答、コメントがあると、segmentfaultシステムはこの質問に注目しているユーザーを遍歴し、一度にユーザーにメッセージを送信します.
パブリケーション・サブスクリプション・モードを一歩一歩実装する方法を見てみましょう.
  • まず、segmentfaultの問題システムなどのパブリッシャを指定します.
  • は、次に、サブスクライバ(問題システムのレコードテーブル)
  • に通知するためにコールバック関数を格納するためのキャッシュリストをパブリッシャに追加する.
  • 最後に、パブリッシャがメッセージを発行すると、キャッシュリストを巡回し、内部のコールバック関数(レコードテーブルを巡回し、メッセージを1つずつ送信)
  • が順次トリガーされる.
    コールバック関数にいくつかのパラメータを加えることもでき、サブスクライバはこれらのパラメータを受信し、それぞれの処理を行うことができます.
    var sgQuestionSystem = {};    //   segmentfault     
    
    /* 
     *     
     * clientList: {
     *    key: [
     *        id: ,        //     
     *        fn: null          //       
     *    ]
     * }
     * 
    */
    sgQuestionSystem.clientList = {};
    
    /* 
     *      (    ),                 
     * key:      
     * id:        
     * fn:        
    */
    sgQuestionSystem.listen = function(key, id, fn) {
        if(!this.clientList[key]) {            //              ,        
            this.clientList[key] = []
        }
       
        this.clientList[key].push({            //     id,                
            id: id,                         
            fn: fn                          
        })
    }
    
    //     (    ),        
    sgQuestionSystem.trigger = function () {
        var key = Array.prototype.shift.call(arguments),    //       
            fns = this.clientList[key];                     //               
        
        if(!fns || fns.length == 0) {                      //                ,   
            return false;                                   
        }
        
        for(var i = 0; i< fns.length; i++) {
             fns[i].fn.apply(this, arguments);               // arguments           ,   key
        }
    }

    簡単なテストを行います.
    //       A
    sgQuestionSystem.listen('questionA', 3, function(questionTitle, content) {
        console.log('           :questionA');
        console.log(' ' + questionTitle + '     ');
        console.log('   :' + content);
    });
    
    //       A
    sgQuestionSystem.listen('questionB', 4, function(questionTitle, content) {
        console.log('           :questionB');
        console.log(' ' + questionTitle + '     ');
        console.log('   :' + content);
    })
    
    //         
    sgQuestionSystem.trigger('questionA', '  A', '       A');
    sgQuestionSystem.trigger('questionB', '  B', '       B');

    これにより,サブスクライバが自分の興味のあるイベントをサブスクライバできる簡単なパブリケーション−サブスクライバモードを実現した.
    皆さん、疲れましたか.
    疲れたらコレクションを注文して、続編を見ることができます.もしあなたがまだ元気なら、続けてください.
    前のセクションでは、問題システムのパブリケーション-サブスクリプションモードを実現しました.今、文章のパブリケーション-サブスクリプションモードを実現します.この場合、どうすればいいですか.上のコードctrl+c,ctrl+vを、名前を変更しますか?それともより良い解決策がありますか?
    答えは明らかにあります.パブリケーション・サブスクリプション機能モジュールを抽出し、個別のオブジェクトに配置することができます.
    var publishSubscribeEvent = {
    
        
        /* 
         *     
         * clientList: {
         *    key: [
         *        id: ,        //     
         *        fn: null          //       
         *    ]
         * }
         * 
        */
        clientList: {},
        
        /* 
         *      (    ),                 
         * key:      
         * id:        
         * fn:        
        */
        listen: function(key, id, fn) {
            if(!this.clientList[key]) {            
                this.clientList[key] = []
            }
           
            this.clientList[key].push({            
                id: id,                         
                fn: fn                          
            })
        },
        
        //     (    ),        
        trigger: function () {
            var key = Array.prototype.shift.call(arguments),
                fns = this.clientList[key];
            
            if(!fns || fns.length == 0) {
                return false;                                   
            }
            
            for(var i = 0; i< fns.length; i++) {
                 fns[i].fn.apply(this, arguments);
            }
        }
    }

    パブリケーション-サブスクリプションをインストールする関数をもう1つ定義します.この関数は、すべてのオブジェクトにパブリケーション-サブスクリプション機能を動的にインストールできます.
    var installPublishSubscribeEvent = function(obj) {
        for(var i in publishSubscribeEvent) {
            obj[i] = publishSubscribeEvent[i];
        }
    }

    もう一度テストして、記事オブジェクトsgArticleSystemにパブリケーション-サブスクリプション機能を動的に追加します.
    var sgArticleSystem = {};
    
    installPublishSubscribeEvent(sgArticleSystem ); 
    
    //       A  
    sgArticleSystem.listen('articleA', 3, function(articleTitle, content) { 
        console.log('           :articleA');
        console.log(' ' + articleTitle+ '     ');
        console.log('   :' + content);
    });
    
    //       B  
    sgArticleSystem.listen('articleB', 4, function(articleTitle, content) { 
        console.log('           :articleB');
        console.log(' ' + articleTitle+ '     ');
        console.log('   :' + content);
    });
    
    //         
    sgArticleSystem.trigger('articleA', 'JavaScript       -    ', '       ');
    sgArticleSystem.trigger('articleB', 'JavaScript         ', '          ');

    はい、このコードは自己測定で問題はありません.もし皆さんが問題を発見したら、フィードバックを歓迎します.これで、指定したオブジェクトにパブリケーション-サブスクリプションモードをインストールできますが、まだ何か機能が少ないのではないでしょうか.
    答えは、イベントの購読をキャンセルする機能が少なくなったことです.例えば、張三は突然この問題の更新動態に注目したくなくなり、問題システムから送られてきたメッセージを受信し続けることを避けるために、張三は前に購読したイベントをキャンセルする必要がある.次に、publishSubscribeEventオブジェクトにremoveメソッドを追加します.
    publishSubscribeEvent.remove = function(key, id) {
        var fns = this.clientList[key];
        
        if(!fns) {                //   key         ,    
            return false;
        }
        
        if(!id) {                //            ,   key       
            fns && (fns.length = 0);
        } else {
            for(var l = fns.length - 1; l >=0; l--) {
                var _id = fns[l].id;
                if(_id == id) {
                    fns.splice(l, 1);    //           
                }
            }
        }
    }
    //     
    var sgArticleSystem = {};
    
    installPublishSubscribeEvent(sgArticleSystem ); 
    
    //      
    sgArticleSystem.listen('articleA', 3, function(articleTitle, content) { 
        console.log('           :articleA');
        console.log(' ' + articleTitle+ '     ');
        console.log('   :' + content);
    });
    
    //      
    sgArticleSystem.listen('articleA', 4, function(articleTitle, content) { 
        console.log('           :articleA');
        console.log(' ' + articleTitle+ '     ');
        console.log('   :' + content);
    });
    
    sgArticleSystem.remove('articleA', 3);    //        
    sgArticleSystem.trigger('articleA', 'JavaScript       -    ', '       ');

    上のコードは原作とは異なり、原作はサブスクリプションを削除する際にコントラストコールバック関数を使用していますが、私はキャッシュリストに識別するための唯一の識別を追加しました.
    これで、私たちのリリース-購読モードの第1部は終わりました.コメントのコレクションを歓迎します.
    附:JavaScriptデザインモードの配布-購読モード(オブザーバーモード)-part 2
    JavaScriptデータ構造とアルゴリズムシリーズ:JSスタックJSキュー-優先キュー、ループキュー
    JavaScript設計モードシリーズ:JavaScript設計モードのポリシーモード