设计模式之发布订阅模式
摘要
本文从上一篇的观察者模式出发,将需求进一步升级,推动代码演化到发布订阅模式。然后介绍了他的实现要点以及它和观察者模式的区别,希望对你理解这两个模式有帮助。
建议你先从观察者模式来看起。
从观察者模式出发到发布订阅者
先回顾观察者模式的代码,如下
// 大漂亮 是女神,有很多的爱慕者
const beauty = {
lover: [], // 容器,保存全部的观察者
notify(){ // 通知全部观察者
this.lover.forEach(fn=>fn())
},
addLover(fn) { // 添加观察者
this.lover.push(fn)
},
removeLover(fn) { // 移除观察者
const idx = this.lover.findIndex(item=>item ===fn);
if(idx !=-1) {
this.lover.splice(idx,1)
}
}
}
const lover1 = () => {console.log('1号爱慕者')}
const lover2 = () => {console.log('2号爱慕者')}
const lover3 = () => {console.log('3号爱慕者')}
beauty.addLover(lover1)
beauty.addLover(lover2)
beauty.addLover(lover3)
beauty.notify()// 1,2,3号
beauty.removeLover(lover1)
beauty.notify()// 2,3号
上面代码的核心要点:
- 一个容器来保存观察者
- 一个动作通知全体观察者
- 两个动作(添加,移除)观察者
注意哈,上面的 目标(大漂亮)与观察者(爱慕者)之间还是耦合在一起(大漂亮亲自添加爱慕者:beauty.addLover(lover) )的。
接下来把上面的代码主角 大漂亮 升级成 ****万人迷 , 她的粉丝也多了,她实在没有精力自己去维护粉丝群了,所以她迫切需要一个第三方(经纪人)来管理她和粉丝之间的联系:
(1)不同的粉丝关注万人迷的不同动向(拍电影和拍广告);
(2)动向要精准通知到不同的粉丝群体。
代码如下:
// 经纪人
const agent = {
// 容器,保存全部的观察者
center: {},
// 添加指定事件的观察者
addLover(eName,fn) {
if( !this.center[eName] )
this.center[eName] = []
this.center[eName].push(fn)
},
// 移除指定事件的观察者
removeLover(eName, fn) {
if( !this.center[eName] ) return
const listener = this.center[eName]
const idx = listener.findIndex(item=>item===fn);
if(idx !=-1) {
listener.splice(idx,1)
}
},
// 发布事件
notify(eName) {
if( !this.center[eName] ) return
const listener = this.center[eName]
listener.forEach(fn => fn())
}
}
// 大漂亮 升级为大明星
// 有了经纪人
const beauty = {
agent: agent,
notify(eName) {
// 让她的经纪人去通知
this.agent.notify(eName )
}
}
const lover1 = () => {console.log('1号观众')}
const lover2 = () => {console.log('2号观众')}
const lover3 = () => {console.log('3号影迷')}
// 经纪人负责管理粉丝
agent.addLover('拍广告', lover1)
agent.addLover('拍广告', lover2)
agent.addLover('拍电影', lover3)
beauty.notify('拍广告')// 1,2号
agent.removeLover('拍广告', lover1)
beauty.notify('拍广告')// 2号
上面的代码的特点是:
(1) 代码:有一个事件管理中心, 结构类似 {事件名1:[观察者1,观察者2],事件名2:[观察者1]}
这样的键值对,属性名表示不同的事件,属性值是一个数组,用来保存观察者们。
(2) 逻辑:观察者(粉丝)和目标(大漂亮)之间多了一层结构(经纪人)。
我们来回顾一下原由:事变得复杂了,需求升级了,所以简单的观察者模式代码升级成了订阅发布者模式了。
一切进步的原由都是更高级的挑战。
发布订阅者模式
GoF在1995年提出23种设计模式中,只有观察者模式(Observer) ,而发布订阅者模式(Publisher/Subscriber) 并不在23中之列。它算是观察者模式的一种特殊扩展(也有人说是:发布订阅模式 又叫做 观察者模式)。他们两个实现结构的区别如下:
举个发布订阅者模式的例子:
你在微博上关注了大V,同时其他很多人也关注了大V。当大V发布动态的时候,微博就会为你们推送这条动态。
大V就是发布者,你是n多个订阅者之一,微博就是经纪人,你和大V是没有直接的消息往来的,全是通过微博来协调的(你的关注,大V的发布动态)。
可以看出:它的特点是目标 和观察者之间有一个独立的第三方来联系。
对比他们的区别
角色个数:
- 观察者模式 : 有两个角色 观察者 + 目标(被观察者)
- 发布订阅模式:有三个角色 发布者+订阅者 + 中间件(额外的事件处理中心)
耦合关系:
- 观察者和被观察者,是松耦合的关系
- 发布者和订阅者,则完全不存在耦合
这里应那句经典的论断:任何软件工程遇到的问题都可以通过增加一个中间层来解决! (比如:观察者模式中观察者和目标并没有解耦,而发布订阅者模式下,发布者和订阅者是解耦的。比如:在windows上安装linux虚拟机来跑linux)
复杂度:
- 观察者模式,简单
- 发布订阅模式,更复杂
观察者模式是不是发布订阅模式?
我没有答案, 但这里有两个基本的事实:
它们的意图相同但结构不同
它们的设计意图是一样:是对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新。(一变 百变)
它们的设计结构是不同的:发布订阅模式相比观察者模式多了一个中间件(事件处理中心)
所以,如果以设计意图来界定设计模式,那它们是一样的,以设计结构来界定,它们就不同。
设计模式并不是固定不变的
设计模式的家族是不断发展的。在1995年提出了23种设计模式,后面增加到了24种,也慢慢有更多的模式已经被总结出来,例如:模块模式、沙箱模式等。
小结
本文介绍了发布订阅者模式的实现代码,及它和观察者模式的区别,希望对你有帮助。
转载自:https://juejin.cn/post/7156528165848875039