浅谈Vue中的观察者模式

在分析响应式原理时,通过getter/setter方法掌握了数据响应式/数据驱动的时机,但对页面中具体的DOM节点修改还不清楚,这是响应式原理的另一个核心——通知指定DOM节点修改:

  • 如何建立视图和数据的关系
  • 如何利用两者关系进行交互

1. 揭秘视图与数据间关系

在文章《Vue数据响应式》中,简单示例了getter和setter的功能:

  • getter:在进行取值的时候进行附加的操作,比如打印取得值
  • setter:在数据发生变化的时候进行一些附加操作,比如通知页面视图更新

这已经可以完成页面的自动更新了,但为了提高页面性能,必须只更新变化的部分,实现最大化的复用。因此需要对数据响应式进行进一步的挖掘,即充分利用getter和setter。

  1. 页面视图中使用数据时,会调用数据的getter方法;
  2. getter方法中可以将使用数据的页面元素收集起来,作用是等到数据改变时可以知道哪些页面元素需要改变;
  3. 数据变化时会触发数据的setter方法;
  4. setter方法可以通知收集的页面元素做出改变。

因此需要一个存储页面元素的对象,同时这个对象能够响应setter,从已有的23种设计模式中检索,发现发布订阅(观察者)模式,非常适合这个场景。

2. 设计模式简介

如今各种编程语言(如java、python、c++、c、JavaScript等)各领风骚,但在计算机软件开发领域的深处,实际上有一套非常成熟的规范或说明书,它就是设计模式,它的存在总结并统一了特定应用场景下的核心处理思想,本节从设计模式的定义和设计模式的基本内容进行展开介绍。

2.1 辨识设计模式

  • 设计模式的概念:一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验总结。
  • 设计模式的目的:
    • 代码的可重用性
    • 代码的可读性
    • 代码的可靠性
  • 设计模式的优点:
    • 便于协作
    • 实现代码编制工程化
  • 个人认识:
    • 设计模式的核心是意图而不是实现方式或代码结构***
    • 设计模式是面向应用场景的
    • 设计模式不是万能的

2.2 设计模式分类

一般优秀的框架都有优秀的逻辑实现方式,而这些实现方式总结、汇聚之后形成了目前经典的23种编程设计模式,而这么多的编程范式中又可以分成三大类,即创建型模式(对象实例化的模式)、结构型模式(将类或对象结合成更大的结构)、行为型模式(类和对象如何交互以及划分责任和算法),如下图所示

3. vue中的观察者模式应用

观察者模式的核心是触发联动,适用于一对多的依赖关系,实现多个对象同时监听一个主体,主体的状态变化会导致多个对象自动更新自己。它在Vue中应用场景就是数据响应式。
但在vue中应用有两处,一是有两个主体(Watcher和Sub)参与的数据响应式;一个是有三个主体参与的事件注册。

3.1 观察者模式——两个主体的直接交互

3.1.1 应用场景再现
let dep = new Dep(); // 目标/发布者
let watcher = new Watcher(); // 观察者/订阅者
dep.addSub(watcher);  // 注册,建立两个主体的交互通道
dep.notify(); // 开始交互

3.1.2 实现模拟

分析结果:

  • 存在两个对象 Dep和Watcher
  • 首先需要注册, 然后才能交互
  • 观察者/订阅者: Watcher
    • update(): 当事件发生时, 具体要做的事情
  • 目标/发布者:Dep
    • subs数组: 存储所有的watcher
    • addSub():添加watcher
    • notify():当变化发生后,调用所有观察者的update方法

// Dependency  目标(发布者)
class Dep{
	constructor(){
		this.subs = []; // 存储所有的观察者
	}
	
	addSub(sub){ // 添加观察者
		if(sub && sub.update){
			this.subs.push(sub);
		}
	}
	
	notify(){ // 通知所有的观察者
		this.subs.forEach(sub => {
			sub.update();
		})
	}
}

// 观察者(订阅者)
class Watcher{
	update(){
		console.log("update"); // 进行更新操作
	}
}

3.1.3 总结

从租房经历分析观察者模式:

  • 发布者/目标:租房中介
  • 观察者/订阅者:关注房源的人(潜在租客)
  • 房源状态改变后,中介会通知潜在租客们

3.2 发布订阅模式——两个主体借助第三方主体的间接交互

3.2.1 应用场景再现
const bus = new Vue();

bus.$on("dataChange", () => {
	console.log("datachange");
})

bus.$on("dataChange", () => {
	console.log("datachange-another one");
});

bus.$emit("dataChange");

3.2.2 实现模拟

分析结果:

  • 存在一个对象
  • 这个对象上面 o n 和 on和 onemit方法
  • 通过$emit发布消息, 则存在一个发布者
  • 通过$on订阅消息,则存在一个订阅者
  • 发布者和订阅者之间的桥梁就是一个特殊对象——信号中心

class EventEmitter{
	constructor(){
		// eventType:[]
		this.subs = {};
	}
	
	// 订阅通知
	$on(eventType, handler){
		this.subs[eventType] = this.subs[eventType] || [];
		this.subs[eventType].push(handler);
	}
	
	// 发布通知
	$emit(eventType){
		if(this.subs[eventType]){
			this.subs[eventType].forEach(handler => {
				handler();
			})
		}
	}
}

3.2.3 总结

还是从租房经历分析这个模式:

  • 信号中心: 租房中介
    • 接收并记录潜在租户的注册信息
    • 向潜在租户发送租房信息
  • 订阅者:潜在租户
    • 向租房中介注册租房需求
  • 发布者:房东
    • 房东有空闲的房子,提供给租房中介房源;
    • 让租房中介发送租房信息

3.3 对比

  • 观察者模式是由具体目标调度,比如 当事件触发,Dep会去调用观察者的方法,所以观察者模式的订阅者和发布者之间存在依赖的,即强耦合关系。因此Vue视图和数据间采用这种方式。
  • 发布/订阅模式是由统一调度中心调用,因此发布者和订阅者之间不需要知道对方的存在,即弱耦合关系。组件间通信和自定义事件采用的是这种方式。


4. 总结

本篇重点分析了视图和数据的关系,并为了解决视图不全局更新的痛点,分析了观察者设计模式的两种实现方式。
后续将模拟Vue响应式原理,从Vue的基本结构、数据劫持、解析指令、发布者、观察者五个角度实现Vue的整个过程。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值