js中的观察者模式和发布订阅模式的区别
1.观察者模式是高耦合,,目标和观察者是直接联系起来的,基于对象
2.发布订阅模式中,双方不知道对方的存在,而观察者模式中,基于自定义事件
3.观察者模式与发布订阅模式都是定义了一个一对多的依赖关系,当有关状态发生变更时则执行相应的更新。
4.不同的是,在观察者模式中依赖于 Subject 对象的一系列 Observer 对象在被通知之后只能执行同一个特定的更新方法,而在发布订阅模式中则可以基于不同的主题去执行不同的自定义事件。
相对而言,发布订阅模式比观察者模式要更加灵活多变。观察者模式和发布订阅模式本质上的思想是一样的,而发布订阅模式可以被看作是观察者模式的一个进阶版。
由以上的描述可以看出,发布订阅模式是松散耦合的,而观察者模式强耦合。
5.在观察者模式中,观察者是知道Subject的,Subject一直保持对观察者进行记录。然而,在发布订阅模式中,发布者和订阅者不知道对方的存在。它们只有通过调度中心进行通信。
在发布订阅模式中,组件是松散耦合的,正好和观察者模式相反。
观察者模式大多数时候是同步的,比如当事件触发,Subject就会去调用观察者的方法。而发布-订阅模式大多数时候是异步的(使用消息队列)
观察者模式的场景:Vue的依赖追踪,原生事件。
发布订阅模式的场景: React的合成事件,vue组件间通信的EventBus。
观察者模式例子:
class Subject {
construct(){
this.observes = []
}
addSub(observe) {
if(!this.observes[observe]){
this.observes.push(observe)
}
}
notice() {
this.observes.map((item,index) => {
item.update()
})
}
remove(observe) {
let index = this.observes[observe]
if(index == undefined) {
throw new Error(`事件未注册`);
}else {
this.observes,splice(index, 1)
}
}
}
class Oberver() {
construct(name) {
this.name = name
}
update() {
console.log('name is change,' this.name)
}
}
发布订阅者模式:
class Subject {
construct() {
this.events = {} // 注册的事件对象数组
}
on(eventType,handler) {
if(!this.events.hasOwnProperty(eventType)) { // 加入事件没有被注册过
this.events[eventType] = []
}
if(typeof(handler) == 'function'){
this.events[eventType].push(handler)
} else {
throw new Error('缺少事件函数');
}
return this // 链式操作
}
emit(eventType,...arg) {
if( !this.events[eventType]) {
throw new Error(`${eventType} 事件未注册`)
}else if(this.events.hasOwnProperty(eventType)) {
this.events[eventType].forEach(item, key) {
this.events[eventType].apply(null,args)
}
}
return this // 链式操作
}
cancel(eventType,handler) {
if(!this.events[eventType]) {
throw new Error('`${eventType} 事件未注册`')
}else if(typeof(handler !='function'){
throw new Error('`取消的事件函数不正确`')
}else {
this.events[eventType].forEach( (item, key, arr) => {
if(item == handler) {
arr.splice(key,1)
}
})
return this // 链式操作
}
}
}
// demo
let callback = function () {
console.log('我是回调函数');
}
let pubsub = new PubSub();
pubsub.on('completed', (...args) => {
console.log(args.join(' '));
}).on('completed', callback);
pubsub.emit('completed', '今天', '是个好日子');
pubsub.off('completed', callback);
pubsub.emit('completed', '明天', '不是');