观察者模式(Observer Pattern)
观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新。观察者模式属于行为型模式,行为型模式关注的是对象之间的通讯,观察者模式就是观察者和被观察者之间的通讯。
观察者模式有一个别名叫“发布-订阅模式”,或者说是“订阅-发布模式”,订阅者和订阅目标是联系在一起的,当订阅目标发生改变时,逐个通知订阅者。我们可以用报纸期刊的订阅来形象的说明,当你订阅了一份报纸,每天都会有一份最新的报纸送到你手上,有多少人订阅报纸,报社就会发多少份报纸,报社和订报纸的客户就是上面文章开头所说的“一对多”的依赖关系。
发布订阅模式(Pub-Sub Pattern)
其实24种基本的设计模式中并没有发布订阅模式,上面也说了,他只是观察者模式的一个别称。 但是经过时间的沉淀,似乎他已经强大了起来,已经独立于观察者模式,成为另外一种不同的设计模式。 在现在的发布订阅模式中,称为发布者的消息发送者不会将消息直接发送给订阅者,这意味着发布者和订阅者不知道彼此的存在。在发布者和订阅者之间存在第三个组件,称为消息代理或调度中心或中间件,它维持着发布者和订阅者之间的联系,过滤所有发布者传入的消息并相应地分发它们给订阅者。
举一个例子,你在微博上关注了A,同时其他很多人也关注了A,那么当A发布动态的时候,微博就会为你们推送这条动态。A就是发布者,你是订阅者,微博就是调度中心,你和A是没有直接的消息往来的,全是通过微博来协调的(你的关注,A的发布动态)。
观察者模式和发布订阅模式有什么区别?
我们先来看下这两个模式的实现结构:
观察者模式: 观察者(Observer)直接订阅(Subscribe)主题(Subject),而当主题被激活的时候,会触发(Fire Event)观察者里的事件。
class Family {
constructor(name, role) {
this.name = name
this.role = role
// 存储观察者
this.subs = []
}
publish(doing) {
this.subs.forEach(sub => sub.cb(`${sub.subscribe.role}(${sub.subscribe.name}) 孩子(${this.name})在${doing}`))
}
subscribe(target, cb) {
target.subs.push({
subscribe: this,
cb
})
}
}
const mom = new Family('雪殷', 'mon')
const father = new Family('重楼', 'father')
const child = new Family('地瓜', 'child')
mom.subscribe(child, (doing) => console.log(doing))
father.subscribe(child, (doing) => console.log(doing))
child.publish('做运动')
child.publish('玩王者荣耀')
发布订阅模式: 订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Topic),当发布者(Publisher)发布该事件(Publish topic)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。
// 事件中心
const Event = {
// 事件队列
events: Object.create(null),
// 订阅者
on: (type, cb) => {
let events = Event.events[type]
if (events === undefined) {
Event.events[type] = events = []
}
events.push(cb)
},
// 发布者
emit: (type) => {
let events = Event.events[type]
if (events === undefined) return
events.forEach(cb => cb())
},
off: (type, cb) => {
if (type === 'all') return Event.events = Object.create(null)
let events = Event.events[type]
if (events === undefined) return
for (let i = events.length - 1; i >= 0; i--) {
if (events[i] === cb) {
events.splice(i, 1)
}
}
}
}
// on
Event.on('click', () => {
console.log('click 1')
})
Event.on('change', () => {
console.log('change 1')
})
const input = () => console.log('input 1')
Event.on('input', input)
// emit
Event.emit('click')
Event.emit('change')
// off
Event.off('click', () => {
console.log('click 1')
})
Event.off('input', input)
Event.off('all')
console.log(Event)
【笔记不易,如对您有帮助,请点赞,谢谢】