1. 程式人生 > 實用技巧 >js設計模式——釋出訂閱模式

js設計模式——釋出訂閱模式

概念

釋出訂閱模式又叫觀察者模式,它定義物件間一對多的依賴關係,當一個物件狀態發生改變時,所有依賴於它的物件都將得到通知。

案例

在js設計模式與開發實踐一書中使用的是樓盤資訊更新發布的案例。大概內容是:想要買房的人們會訂閱自己想要的房產資訊,如果房產資訊有更新,就會發布給這些人。

比如佩奇想買一個房子,他可以在售樓處(salesOffices)去訂閱這類房產訊息,售樓處會將佩奇訂閱的資訊填寫(listen)在客戶訂閱表中(clientList),當有房子出來時,售樓處就會發送(trigger)資訊給佩奇。

主要內容就是:

salesOffices={
    clientList:[],
    listen:
function, trigger:function }

程式碼如下:

<!DOCTYPE html>
<html>
<head>
    <title>釋出訂閱</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>

</body>
<script type="text/javascript">
    var consoleText=function
(text) { // body... let body=document.body; let div=document.createElement('div'); div.innerHTML=text; body.appendChild(div); } //簡單釋出-訂閱模式 var salesOffices={}; salesOffices.clientList=[]; salesOffices.listen=function(fn){ this.clientList.push(fn); } salesOffices.trigger
=function(){ for(var i=0,l=this.clientList.length;i<l;i++){ this.clientList[i].apply(this,arguments); } } salesOffices.listen(function(price,s){ consoleText('佩奇您好,現在有新樓盤:價格:'+price+",面積:"+s); }) salesOffices.listen(function(price,s){ consoleText('小紅您好,現在有新樓盤:價格:'+price+",面積:"+s); }) salesOffices.trigger(6000000,120); </script> </html>

如果現在佩奇發現房價太高了,自己的預算只能付得起80平房子的首付,售樓處再給佩奇發120平的房子只會扎佩奇的心,所以佩奇只想訂閱80平的房子的訊息。

這時候只需要將訂閱表分為不同的型別,想要哪種房子的訊息就去哪張表填寫資訊,現在佩奇的資訊只能出現在80平的表上了。

當有80平的資訊出來時,只需給將80平訂閱表的使用者傳送訊息即可

salesOffices={
    clientList:{
        square80:[],
        square120:[],
    },
    listen:function,
    trigger:function
}

程式碼如下:

<!DOCTYPE html>
<html>
<head>
    <title>釋出訂閱</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>

</body>
<script type="text/javascript">
    var consoleText=function (text) {
        // body...
        let body=document.body;
        let div=document.createElement('div');
        div.innerHTML=text;
        body.appendChild(div);
    }


//可選型別釋出-訂閱模式
    var salesOffices={};
    salesOffices.clientList={};

    salesOffices.listen=function(key,fn){
        //將key型別的訂閱儲存起來
        if(!this.clientList[key]){
            this.clientList[key]=[]
        }
        this.clientList[key].push(fn);
    }

    salesOffices.trigger=function(){
        let key=Array.prototype.shift.call(arguments);
        fns=this.clientList[key];
        if(!fns||fns.length===0){
            return false;
        }
            for(var i=0,l=fns.length;i<l;i++){
            fns[i].apply(this,arguments);
        }
    }

    salesOffices.listen("square80",function(price){
        consoleText('小明您好,現在有新樓盤80平:價格:'+price);
    })

    salesOffices.listen("square80",function(price){
        consoleText('小李您好,現在有新樓盤80平:價格:'+price);
    })

    salesOffices.listen("square110",function(price){
        consoleText('小紅您好,現在有新樓盤110平:價格:'+price);
    })

    salesOffices.trigger("square80",12000000);

</script>
</html>

佩奇之後找到了心儀的房子,已經不需要售樓處再發訊息了,所以還有取消訂閱的功能。

而這種釋出訂閱的模式很有用,很多行業都可以使用它,所以如果能安裝即用就會很nice

程式碼如下

<!DOCTYPE html>
<html>
<head>
    <title>釋出訂閱</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>

</body>
<script type="text/javascript">
    var consoleText=function (text) {
        // body...
        let body=document.body;
        let div=document.createElement('div');
        div.innerHTML=text;
        body.appendChild(div);
    }

//通用釋出訂閱模式
    var event={
        clientList:{},
        listen:function(key,fn){
            if(!this.clientList[key])
                this.clientList[key]=[];
            this.clientList[key].push(fn);
        },
        trigger:function(){
            var key=Array.prototype.shift.call(arguments);
            var fns=this.clientList[key];
            if(!fns||fns.length===0)
                return false;
            for(var i=0,l=fns.length;i<l;i++){
                fns[i].apply(this,arguments);
            }
        },
        remove:function(key,fn){    //取消訂閱
            var fns=this.clientList[key];
            if(!fns){// 如果 key 對應的訊息沒有被人訂閱,則直接返回
                return false;
            }

            if(!fn){ // 如果沒有傳入具體的回撥函式,表示需要取消 key 對應訊息的所有訂閱
                fns&&(fns.length=0);
            }else{
                for(var l=fns.length;l>=0;l--){
                    if(fns[l]===fn){
                        fns.splice(l,1);
                    }
                }
            }
        }

    }



    var installEvent=function(obj){
        for(let i in event){
            obj[i]=event[i];
        }
    }

    var salesOffices={};
    installEvent(salesOffices);

    //key的選擇,我覺得應該是某個變化的條件
    salesOffices.listen("square80",f1=function(price){
        consoleText('小明您好,現在有新樓盤80平:價格:'+price);
    })

    salesOffices.listen("square80",f2=function(price){
        consoleText('小李您好,現在有新樓盤80平:價格:'+price);
    })

    salesOffices.listen("square110",f3=function(price){
        consoleText('小紅您好,現在有新樓盤110平:價格:'+price);
    })

    salesOffices.remove("square80",f2);
    salesOffices.trigger("square80",80);
</script>
</html>