javascript 简单实现观察者模式和发布-订阅模式 1. 观察者模式1.1 什么是观察者模式1.2 代码实现 2. 发布-订阅模式2.1 什么是发布-订阅模式2.2 代码实现2.2.1 基础版2.2.2 取消订阅2.2.3
概念:观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。
如何理解这句话呢?来举个生活中的例子
学生小明情绪比较容易波动,所以当小明的情绪发生变化时,父母和老师希望及时获得通知,以便可以采取适当的措施来帮助他。
这样父母和老师就能及时了解小明的情绪状态,当小明情绪低落时,他们可以给予他关心、安慰和支持。
在这个例子中,小明就是被观察者,而父母和老师都是观察者。
观察者模式有何应用呢?
Vue的响应式就是基于观察者模式的,下面就来简单实现一下它的代码。
// 被观察者 学生class Subject { constructor() { this.state = "happy"; this.observers = []; // 存储所有的观察者 } //新增观察者 add(o) { this.observers.push(o); } //获取状态 getState() { return this.state; } // 更新状态并通知 setState(newState) { this.state = newState; this.notify(); } //通知所有的观察者 notify() { this.observers.forEach((o) => o.update(this)); }}// 观察者 父母和老师class Observer { constructor(name) { this.name = name; } //更新 update(student) { console.log(`亲爱的${this.name} 通知您当前学生的状态是${student.getState()}`); }}let student = new Subject();let parent = new Observer("父母");let teacher = new Observer("老师");//添加观察者student.add(parent);student.add(teacher);//设置被观察者的状态student.setState("sad");
发布订阅模式跟观察者模式很像,它们其实都有发布者和订阅者,但是他们是有区别的:
为了更好区分这两种设计模式,接着上述例子。
通过发布订阅模式,小明不需要直接告诉每位老师他的情绪状态,而是通过情绪监测系统自动发布消息给所有订阅了他情绪状态的老师。这种发布者不直接接触到订阅者的模式,就是发布订阅模式。
那么发布订阅模式有何应用呢?
Vue的EventBus事件总线其实就是用了发布订阅模式。用法如下:
1.创建全局事件总线
// main.jsimport Vue from "vue"Vue.prototype.$bus = new Vue()
通过on订阅事件
//组件Aexport default{ mounted(){ // 监听事件的触发 this.$bus.$on("sendMsg", data => { console.log(data)//身体健康 }) }, beforeDestroy(){ // 取消监听 this.$bus.$off("sendMsg") }}
通过emit发布事件
//组件B<template> <button @click="handlerClick">点击发送数据</button></template>export default{ methods:{ handlerClick(){ this.$bus.$emit("sendMsg", "身体健康") } }}
了解了EventBus的使用后,那么接下来就来手动实现一个EventBus。
实现目标:使用 $on 订阅事件,使用 $emit 发布事件。
主要思路:
class EventBus { constructor() { // 缓存列表,用来存放注册的事件与回调 this.cache = {}; } // 订阅事件 on(name, cb) { // 如果当前事件没有订阅过,就给事件创建一个队列 if (!this.cache[name]) { this.cache[name] = []; //由于一个事件可能注册多个回调函数,所以使用数组来存储事件队列 } this.cache[name].push(cb); } // 触发事件 emit(name, ...args) { // 检查目标事件是否有监听函数队列 if (this.cache[name]) { // 逐个调用队列里的回调函数 this.cache[name].forEach((callback) => { callback(...args); }); } }}// 测试let eventBus = new EventBus();// 订阅事件eventBus.on("teacherName1", (pos, state) => { console.log(`订阅者小陈老师,小明同学当前在${pos},心情状态是${state}`);});eventBus.on("teacherName1", (pos, state) => { console.log(`订阅者小陈老师,小明同学当前在${pos},心情状态是${state}`);});eventBus.on("teacherName2", (pos, state) => { console.log(`订阅者小李老师,小明同学当前在${pos},心情状态是${state}`);});// 发布事件eventBus.emit("teacherName1", "教室", "伤心");eventBus.emit("teacherName2", "操场", "开心");
输出结果:
实现目标:增加 off 方法取消订阅。
class EventBus { constructor() { // 缓存列表,用来存放注册的事件与回调 this.cache = {}; } // 订阅事件 on(name, cb) { // 如果当前事件没有订阅过,就给事件创建一个队列 if (!this.cache[name]) { this.cache[name] = []; //由于一个事件可能注册多个回调函数,所以使用数组来存储事件队列 } this.cache[name].push(cb); } // 触发事件 emit(name, ...args) { // 检查目标事件是否有监听函数队列 if (this.cache[name]) { // 逐个调用队列里的回调函数 this.cache[name].forEach((callback) => { callback(...args); }); } } // 取消订阅 off(name, cb) { const callbacks = this.cache[name]; const index = callbacks.indexOf(cb); if (index !== -1) { callbacks.splice(index, 1); } }}// 测试let eventBus = new EventBus();let event1 = function (...args) { console.log(`通知1-订阅者小陈老师,小明同学当前心情状态:${args}`)};let event2 = function (...args) { console.log(`通知2-订阅者小陈老师,小明同学当前心情状态:${args}`)};// 订阅事件eventBus.on("teacherName1", event1);eventBus.on("teacherName1", event2);// 取消订阅事件1eventBus.off('teacherName1', event1);// 发布事件eventBus.emit("teacherName1", "教室", "上课", "打架", "愤怒");eventBus.emit("teacherName2", "教室", "上课", "打架", "愤怒");
输出结果:
实现目标:增加 once 方法只订阅一次。
class EventBus { constructor() { // 缓存列表,用来存放注册的事件与回调 this.cache = {}; } // 订阅事件 on(name, cb) { // 如果当前事件没有订阅过,就给事件创建一个队列 if (!this.cache[name]) { this.cache[name] = []; //由于一个事件可能注册多个回调函数,所以使用数组来存储事件队列 } this.cache[name].push(cb); } // 触发事件 emit(name, ...args) { // 检查目标事件是否有监听函数队列 if (this.cache[name]) { // 逐个调用队列里的回调函数 this.cache[name].forEach((callback) => { callback(...args); }); } } // 取消订阅 off(name, cb) { const callbacks = this.cache[name]; const index = callbacks.indexOf(cb); if (index !== -1) { callbacks.splice(index, 1); } } // 只订阅一次 once(name, cb) { // 执行完第一次回调函数后,自动删除当前订阅事件 const fn = (...args) => { cb(...args); this.off(name, fn); }; this.on(name, fn); }}// 测试let eventBus = new EventBus();let event1 = function (...args) { console.log(`通知1-订阅者小陈老师,小明同学当前心情状态:${args}`)};// 订阅事件,只订阅一次eventBus.once("teacherName1", event1);// 发布事件eventBus.emit("teacherName1", "教室", "上课", "打架", "愤怒");eventBus.emit("teacherName1", "教室", "上课", "打架", "愤怒");eventBus.emit("teacherName1", "教室", "上课", "打架", "愤怒");
输出结果:
写作不易,你的一赞一评,就是我前行的最大动力。如有问题,欢迎指出!
来源地址:https://blog.csdn.net/weixin_43288600/article/details/131968091
--结束END--
本文标题: JavaScript 简单实现观察者模式和发布-订阅模式
本文链接: https://www.lsjlt.com/news/376963.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-04-03
2024-04-03
2024-04-01
2024-01-21
2024-01-21
2024-01-21
2024-01-21
2023-12-23
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0