订阅-发布模式是设计模式中的一种应用场景比较多的模式,定义了一种对象间一对N的依赖关系(注意是一对N),当一个对象的状态发生改变时,全部依赖于它的对象都将获得更新。
订阅发布模式相较于观察者模式能够说是一种改进,其比观察者模式耦合性低。javascript
观察上图能够看到订阅发布模式大体能够分为三个角色,分别为发布者、管理中心(姑且这么称呼)、订阅者。管理中心就像一个中转站,维系着订阅者和发布者之间的关系,中转着各类不一样发布者发布的信息,并将其准确无误的派发到每种订阅者手中,有点儿像快递小哥儿哈(更像快递柜...)java
下面来说如何用js实现一个简单的订阅发布模式
首先咱们要设想下管理中心的功能:设计模式
有了功能咱们就要开始设想如何实现了,这里咱们假设每一个发布者只有发布一种消息,首先在有发布者A,发布者B,发布者C...的状况下就须要进行身份(key)辨认了,咱们先设置一个处理队列,分别存放每一个发布者要发布的信息。数组
let queue = {
'发布者A的key': [
function 订阅者a要这么作(){},
function 订阅者b要这么作(){}
]
}复制代码
而后咱们已经存储了发布者A和订阅者a、b之间的关系了,下面咱们还要让A发布的时候分别执行a、b的订阅方法。因此基本代码为:函数
const bus = function (){
let queue = {}, emit, on, off
on = (key, fn) =>{
if(!queue[key]){
queue[key] = []
}
queue[key].push(fn)
}
emit = (key, ...args) => {
let fns = queue[key]
if(!fns || !fns.length){
return
}
fns.map(_ => {
_(...args) })
}
return {
$on: on,
$emit: emit
}
}复制代码
稍微解释下:$on方法即为收集依赖的方法,经过其能够将发布者与订阅者们的关系放处处理队列中,而后$emit方法为发布者发布更新的方法,当发布者发布更新的时候,对应key的函数组便会依次执行达到更新每一个订阅者的目的。ui
上述代码已经基本实现了功能,美中不足就是不能将发布者和订阅者“分手”,有合必有分,因此咱们还须要一个分手的方法。
大致思路:订阅者经过发布者的key来找到拟分手的发布者,而后提供本身的处理方法名字,而后在处理队列中删除,两不相欠,若是发布者想彻底退出还要把此key对应的处理方法都清空。spa
完整代码:设计
// 这里的bus就是一个管理中心,全部订阅者发布者能够经过其进行交流
const bus = ()=> {
let queue = {}, emit, on, off
on = (key, fn) =>{
if(!queue[key]){
queue[key] = []
}
queue[key].push(fn)
}
emit = (key, ...args) => {
let fns = queue[key]
if(!fns || !fns.length){
return
}
fns.map(_ => {
_(...args)
})
}
off = (key, fn) => {
if(queue[key] === undefined || queue[key].length === 0){
return
}
if(fn !== undefined){
queue[key] = queue[key].filter(_ => _ !== fn)
} else{
queue[key] = []
}
}
return {
$on: on,
$emit: emit,
$off: off
}
}复制代码
好了,这就是订阅发布模式的简易实现,有兴趣的小伙伴能够在控制台试下如下代码~code
let bu = new bus()
function fn1(val){
console.log(`fn1: ${val}`)
}
function fn2(val){
console.log(`fn2: ${val}`)
}
function fn3(val){
console.log(`fn3: ${val}`)
}
// 第一个监听
bu.$on('test', fn1)
// 第二个监听
bu.$on('test', fn2)
// 发布消息
bu.$emit('test', 'blablabla')
// 解绑第一个
bu.$off('test', fn1)
// 第三个监听
bu.$on('test', fn3)
// 发布消息
bu.$emit('test', 'hahaha')
// 所有解绑
bu.$off('test')
// 发布消息
bu.$emit('test', '???')复制代码
若有错误,还望你们指出,谢谢🙏~cdn