JavaScript 浅谈观察者模式 前端设计模式

2、观察者模式

2.1、观察者模式

2.1.1、前言

定义一种一对多的依赖关系,当一个对象发生变化时,所有依赖于它的对象都会自动收到通知并更新。

两个角色:

  1. Subject(主题/被观察者)
  1. Observer(观察者)

观察者模式一般至少有一个 Subject(主题) ,可以有多个Observer(观察者)。

二者关系: Subject(主题)主动建立与观察者的关系。

Subject(主题/被观察者):至少要有三个方法------添加观察者、移除观察者、通知观察者。

2.1.2、代码
javascript 复制代码
		<input type="text" id="app" oninput="handleInput(event)">
<script>
			// 主题,接收状态变化,并通知每个观察者
			class Subject {
				constructor() {
					this.observers = []
				}
				// 新增观察者
				addObserver(observer) {
					this.observers.push(observer)
				}
				// 通知每个观察者
				notify(state) {
					this.observers.forEach(observer => {
						observer.update(state)
					})
				}
				removeObserver(observer) {
					const index = this.observers.indexOf(observer);
					if (index !== -1) {
						this.observers.splice(index, 1);
					}
				}
			}
			// 观察者,等待被通知
			class Observe {
				constructor(name) {
					this.name = name
				}
				update(state) {
					console.log(`${this.name} 获取到最新值:${state}`);
				}
			}

			const handleInput = (e) => {
				const event = e || event
				const value = event.target.value
				// 实例化一个主题
				const sub = new Subject()
				// 实例化两个观察者 一个沐歌,一个沐夏
				const muge = new Observe('沐歌')
				const muxi = new Observe('沐夏')
				// 添加观察者实例
				sub.addObserver(muge)
				sub.addObserver(muxia)
				// 状态改变,通知所有观察者
				sub.notify(value)
			}
		</script>

2.2、发布订阅模式

2.2.1、前言

发布订阅模式在观察者模式的基础上加入了 事件调度中心,提供更灵活的控制,适用于复杂的消息交互场景。

观察者模式是经典的设计模式,观察者和目标之间直接交互,适合简单的一对多通知。

2.2.1、代码
复制代码
/*
 * @Author: muge
 * @Date: 2021-05-21 18:46:09
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2023-03-09 16:37:47
 */
//仿vue-$on $emit
class Event {
  // 首先定义一个事件对象,用来装事件数组(多个订阅者)
  handlers = {};
  // 订阅(事件添加方法) type=事件名 callback=回调函数
  $on(type, callback) {
    if (!this.handlers[type]) {
      // 没有则初始化
      this.handlers[type] = [];
    }
    // 存入该事件
    this.handlers[type].push(callback);
  }
  // 触发事件 type=事件名 params=参数
  $emit(type, params) {
    // 若没有注册该事件则抛出错误
    if (!this.handlers[type]) return new Error("未注册该事件");
    // 事件触发
    this.handlers[type].forEach((callback) => callback(params));
  }
  // 取消订阅 type=事件名 callback=回调函数
  $unsubscribe(type, callback) {
  // 无效事件抛出异常
  if (!this.handlers[type]) return new Error("未注册该事件");
    // 执行回调
	callback&&callback()
	// 删除事件
	delete this.handlers[type];
  }
}
// 创建一个event实例
const sub = new Event();
// 订阅事件changeInputValue onLaod
sub.$on("changeInputValue", (params) => {
  console.log("params", params);
});
sub.$on("onLaod", (params) => {
	console.log("params", params);
  });
console.log('当前的事件列表',sub.handlers);
// 事件触发
sub.$emit("changeInputValue", "最新的值是:1");
sub.$unsubscribe('changeInputValue',()=>{
	console.log('取消订阅,执行的回调');
})
console.log('changeInputValue-事件取消',sub.handlers);

DOM事件也是发布订阅模式。订阅window的onload事件,当window加载完毕时会向订阅者发布消息,执行相应的回调函数。

复制代码
window.addEventListener('onload', function () {
    console.log('loaded!')
})
相关推荐
对空六课18 分钟前
支持注意力分析的热力图工具有哪些?
前端·数据库·数据分析
Csvn1 小时前
Vue3 响应式与编译:依赖收集如何升级为节点级靶向更新
前端
星栈2 小时前
pnpm 12 升级实测
前端·javascript
Sirens.3 小时前
Java并发锁详解:六类锁策略与 synchronized 底层原理
java·前端·算法
Ai-_Man3 小时前
您您这可以把Microsofat Copilot的多个会话比如说。左侧的多个会话一次性导出吗?不是单条会话里面的多次会对话。AI导出鸭
javascript·人工智能·ai·小程序·电脑·copilot
特创数字科技4 小时前
一个纯本地运行的图片处理工具:压缩 / 裁剪 / 九宫格 / 圆角 / 滤镜 / 拼图 / 水印,终生使用
前端
geovindu4 小时前
rust: Composite Pattern
开发语言·后端·设计模式·rust·组合模式
IT_陈寒5 小时前
Vue的v-if和v-for混用居然是个天坑
前端·人工智能·后端
天衍四九-5 小时前
【无标题】
前端·spring boot·mysql·nginx·docker
广州华水科技5 小时前
2026年单北斗GNSS变形监测系统推荐榜单,解锁GNSS位移监测新高度
前端