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>

 

posted @ 2020-10-14 15:29  ellenxx  阅读(301)  评论(0编辑  收藏  举报