观察者模式(Observer)
它是软件设计模式的一种。在此种模式中,一个目标对象管理着所有相依(依赖)于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统
观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新,简单来说,观察者模式就是,一个对象(被观察者)的状态发生改变时,会通知所有依赖它的对象(观察者),观察者模式有一个别名叫发布-订阅模式
发布-订阅模式(Publisher-Subscriber)
其实 23 种基本的设计模式中并没有发布-订阅模式,上面也说了,他只是观察者模式的一个别称。但是经过时间的沉淀,似乎他已经强大了起来,已经独立于观察者模式,成为另外一种不同的设计模式。在现在的发布订阅模式中,称为发布者的消息发送者不会将消息直接发送给订阅者,这意味着发布者和订阅者不知道彼此的存在。在发布者和订阅者之间存在第三个组件,称为消息代理或调度中心或中间件,它维持着发布者和订阅者之间的联系,过滤所有发布者传入的消息并相应地分发它们给订阅者
观察者模式 和 发布-订阅模式的区别
观察者模式是,当被观察者的数据发生变化时,调用被观察者的 notify 方法,去通知所有观察者执行 update 方法进行更新
对于发布-订阅模式,首先发布者与订阅者互相并不知道彼此的存在,他们是通过事件中心来进行调度的,发布者在事件中心发布一个对应的事件主题,订阅者在事件中心订阅一个事件主体,当订阅者去触发 emit 时就去执行发布者所发布的事件
Vue 展示了其设计模式的案例体现,Vue 的双向数据绑定使用了观察者模式,其中央事件总线 EventBus 使用了发布-订阅模式
详细请看:https://blog.51cto.com/u_15283585/2959669
观察者模式和发布-订阅模式的区别:https://blog.csdn.net/qq_38128179/article/details/111307528
手写观察者模式
// 被观察者:Dep
class Dep {
constructor() {
// 记录所有的观察者
this.subs = []
}
// 添加观察者
addSub(sub) {
// 如果该观察者存在且有 update 方法,就将其添加到 subs 数组中
if (sub && sub.update) {
this.subs.push(sub)
}
}
// 移除观察者
removeSub(sub) {
if (this.subs.length) {
let index = this.subs.indexOf(sub)
if (index > -1) {
this.subs.splice(index, 1)
}
}
}
// 发布更新通知
notify() {
this.subs.forEach(item => {
item.update()
})
}
}
// 观察者:Watcher
class Watcher {
update() {
console.log("****更新相关数据****")
}
}
let dep = new Dep();
let watcher1 = new Watcher();
let watcher2 = new Watcher();
// 添加新的观察者
dep.addSub(watcher1)
dep.addSub(watcher2)
dep.removeSub(watcher2)
// 发布
dep.notify();
手写发布-订阅模式
class Observer {
constructor() {
this.message = {} // 消息队列
}
/**
* `$on` 向消息队列添加内容
* @param {*} type 事件名 (事件类型)
* @param {*} callback 回调函数
*/
$on(type, callback) {
// 判断有没有这个属性(事件类型)
if (!this.message[type]) {
// 如果没有这个属性,就初始化一个空的数组
this.message[type] = [];
}
// 如果有这个属性,就往他的后面 push 一个新的 callback
this.message[type].push(callback);
}
/**
* $off 删除消息队列里的内容
* @param {*} type 事件名 (事件类型)
* @param {*} callback 回调函数
*/
$off(type, callback) {
// 判断是否有订阅,即消息队列里是否有 type 这个类型的事件,没有的话就直接 return
if (!this.message[type]) return;
// 判断是否有 callback 这个参数
if (!callback) {
// 如果没有 callback,就删掉整个事件
this.message[type] = undefined;
return;
}
// 如果有callback,就仅仅删掉 callback 这个消息(过滤掉这个消息方法)
this.message[type] = this.message[type].filter((item) => item !== callback);
}
/**
* $emit 触发消息队列里的内容
* @param {*} type 事件名 (事件类型)
*/
$emit(type) {
// 判断是否有订阅
if(!this.message[type]) return;
// 如果有订阅,就对这个 `type` 事件做一个轮询 (for 循环)
this.message[type].forEach(item => {
// 挨个执行每一个消息的回调函数 callback
item();
});
}
/**
* $once 只订阅一次
* @param {*} type 事件名 (事件类型)
* @param {*} callback 回调函数
*/
$once(type, callback) {
let one = (...args) => {
// 执行发布
callback(args);
// 停止订阅
this.$off(type, one);
}
// 注册重构后的一次监听事件
this.$on(type, one);
}
}
let ob = new Observer();
let func = function () {
console.log("我是小刘")
}
ob.$on("name", func);
ob.$emit("name");
// 注销对应的事件
ob.$off("name", func);
// 再次触发对应的事件,就不会触发了
ob.$emit("name");
// 只订阅一次
ob.$once("name1", function () {
console.log("我是小李");
})
ob.$emit("name1");
网友评论