js发布订阅模式

订阅-发布模式

 再开始之前先简单介绍下订阅-发布模式,因为这种设计模式在vue代码中起到比较关键的作用。
首先,简单来说订阅-发布模式是一种定义一对多依赖关系的设计模式,当一个对象状态发生变化时候,所依赖于他的所有对象都将得到通知。
 举个简单例子:很多学生到书店买书,A同学定了一本《js高程》,B同学定了一本《js设计模式》……,但是书店的好多书厂家还没发货,买书者不可能天天跑过去问书到了没,这样书店也应付不过来,买书者也耗费大量时间。所以一般这种情况,书店会留下买书者信息,等书到了通知买书者就ok了。这个例子里,买书者就充当订阅者,书店就是发布者。
既然是订阅-发布模式,那么它应当具备以下特征:

  • 有许多订阅者,有一个发布者
  • 发布者具有监听订阅者需要订阅什么东西的能力
  • 发布者具有发布信息能力,即自身状态改变通知所有订阅者的能力

下面根据上面的特点来实现一个最简单的发布订阅模式 :

// 创建一个发布者
const publisher = {};
//发布者储存订阅者信息的对象
const informations = {}
//给发布者赋予监听订阅者和它需要信息的能力,sbuscriber_key--订阅者标识,fn--订阅者需要的信息或者服务
publisher.listen = (sbuscriber_key,fn) => {
    if(!informations[sbuscriber_key] ){       //如果订阅者没有订阅过信息,新建一个数组存储订阅者信息(一个订阅者可能订阅多条信息)
        informations[sbuscriber_key] = [];
    }
    informations[sbuscriber_key].push(fn);    
}
//给发布者赋予通知所有订阅者信息的能力
publisher.inform = (sbuscriber_key,...arg) => {
    if(!informations[sbuscriber_key] || informations[sbuscriber_key].length === 0){
        return new Error('订阅信息不存在')
    }
    informations[sbuscriber_key].forEach(fn => {
        fn.call(this,...arg)
    });
}

publisher.listen('A',bookName => {
    console.log(bookName+'---到了可以过来取了')
}) //A订阅一本书
publisher.listen('B',(bookName,price) => {
    console.log(bookName+'---到了,价格'+price+'是否还要')
}) //B订阅一本书

//书到了,发布者通知订阅者
publisher.inform('A','js高程')        //js高程---到了可以过来取了
publisher.inform('B','js设计模式',50) //js设计模式---到了,价格50是否还要

上面的例子里,比如B同学要到很多书店买书看哪个书店到货了,最后要确切知道去哪个书店买书,造成了B同学和书店的耦合,所以这时候班级统一找一个人C登记每个人要卖的书。买书的不用知道去哪个书店买的,书店也不需要知道卖给谁了,统一由C代理,这样C就是该事件的发布者,根据第一个代码实现,把发布者做一个通用实现:

function Publisher(){
    this.informations = {}
}
Publisher.prototype = {
    constructor : Publisher,
    inform: function (sbuscriber_key,...arg){
        if(!this.informations[sbuscriber_key] || this.informations[sbuscriber_key].length === 0){
            return new Error('订阅信息不存在')
        }
        this.informations[sbuscriber_key].forEach(fn => {
            fn.call(this,...arg)
        })
        console.log(this)
    },
    listen: function (sbuscriber_key,fn){
        if(!this.informations[sbuscriber_key] ){       
            this.informations[sbuscriber_key] = [];
        }
        this.informations[sbuscriber_key].push(fn);    
    },
    remove:function (sbuscriber_key){
        if(!this.informations[sbuscriber_key] ){       
            return;
        }
        this.informations[sbuscriber_key].length = 0;
    }
}

const p = new Publisher();
p.listen('A',bookName => {
    console.log(bookName+'---到了可以过来取了')
}) 
p.listen('B',(bookName,price) => {
    console.log(bookName+'---到了,价格'+price+'是否还要')
}) 

p.inform('A','js高程')        
p.inform('B','js设计模式',50) 

给出通用构造函数Pulisher

posted @ 2020-02-21 16:32  逸丶风  阅读(314)  评论(0编辑  收藏  举报