发布-订阅模式

前言

本章主要以javascript作为编程语言进行发布-订阅设计模式的个人理解。全文分为3个部分,大概耗时10分钟。

一、发布-订阅模式的介绍

发布-订阅模式,大学所学习的设计模式的课程中,老师并没有讲到这样的一种设计模式。
之所以会知道,是在学习Vue的数据双向绑定的原理时认识的,Vue的作者尤大就是用发布-订阅模式来实现数据的双向绑定的。
那么到底什么是发布-订阅模式?

举个栗子:我在微信上关注了某个公众号,同时其他人也关注了这个公众号,当这个公众号一推出新的推文时,我们每个关注这个公众号的人就都能收到推新信息。在这个事件中,我们就是订阅者,公众号就是发布者,而微信就是我们中间的沟通桥梁、订阅中心。我们只管订阅,公众号只管更新,彼此互不影响,但当公众号一推新时,我们又能立马收到推新信息,这就是发布-订阅模式。
在这里插入图片描述
设计模式”(Design Pattern)是针对编程中经常出现的、具有共性的问题,所提出的解决方法。

发布-订阅模式要解决的一类问题,就是关于发布者和订阅者两者之间的通讯解耦问题。通讯指的是发布者一更新,订阅者也会跟着自动更新;而解耦指的是发布者和订阅者之间不用再相互依赖,我们不用每时每刻去问公众号什么时候推新,公众号在推新时也不用去向每个人问有没有订阅,彼此之间一个只管订阅、一个只管发布,互不影响。

二、发布-订阅模式和观察者模式的区别

在设计模式中有一种设计模式叫观察者模式,大概概念如下:

一个或多个观察者对目标的状态感兴趣,通过将自己依附在目标对象上以便注册所感兴趣的内容。
目标状态发生改变并且观察者可能对这些改变感兴趣,会发送一个通知消息,调用每个观察者的更新方法。
当观察者不再对目标状态感兴趣时,他们可以简单将自己从中分离。

从概念上看,观察者模式要解决问题的问题,貌似和发布订阅好像是同一类问题。其实在一开始,是没有发布-订阅模式的,或者说发布-订阅模式,被叫成是观察者模式的一种别称。但其实仔细区分的话,这两者还是有不同点的:

  1. 在观察者模式中,订阅者是将自己去注册到发布者中的。
  2. 而在发布-订阅模式中,发布者和订阅者两者间是多了一个订阅中心,两者没有直接关联。如下图所示:
    在这里插入图片描述

打个比方:

  1. 观察者模式就好比上课,我们到教室订阅老师的讲课内容,老师当面给我们发布传授他的知识。
  2. 而发布-订阅模式就是上网课,老师把他要传授的内容录制成网课,发布在网上的某个平台,我们只需要订阅相关的课程就好了。当网课一更新,我们也能立马进行学习。

接下来通过一个应用场景来看他们的不同:
前提假设:我们的页面有多个地方,都需要一个登录异步请求操作获取到数据后,再进行渲染。
问题解析:这个场景可以理解为,当登录完成,数据一更新时,页面元素就跟着做出修改,进行自我的渲染,那用我们的发布-订阅模式和观察者模式分别可以这样写

发布-订阅模式

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<style>
			#title, #nav {
				font-size: 50px;
			}
		</style>
	</head>
	<body>
		<div id='title'>title:</div>
		<div id='nav'>nav:</div>
	</body>
	<script>
		// 定义订阅中心
		let subCenter = {
			subList: {},
			// {login:[cb1,cb2]}
			// 添加订阅
			add(event, callback) {
				if (!this.subList[event]) {	// 判断是否有该订阅事件,有的话就push,没有的话就先新建数组再push
					this.subList[event] = [];
				}
				this.subList[event].push(callback);
			},
			// 发布信息
			notice(event) {
				var cbList = this.subList[event];
				if (!cbList) {	// 如果不存在该订阅事件就退出
					return;
				}
				cbList.forEach((cb) => {	// 遍历执行该订阅事件下的函数
					cb();
				});
			}
		};

		// 订阅者添加订阅(订阅login)
		subCenter.add('login', () => {
			document.getElementById('title').innerHTML = 'title:根据login拿到值了'
		});
		subCenter.add('login', () => {
			document.getElementById('nav').innerHTML = 'nav:根据login拿到值了'
		});

		// 用定时器模拟异步登录事件,发布者发布事件login
		setTimeout(() => {
			subCenter.notice('login');
		}, 3000)
		
	</script>
</html>

从上面的代码我们可以看到,有一个订阅中心,用于存放订阅者(subList)、添加订阅者(add)和发布信息(notice),订阅者只需要将自己想要订阅的事件(login)添加到订阅中心,然后当发布者发布订阅的事件(login)时,订阅了login的订阅者就都能监听到这个事件(login)的发生,并执行相应的回调。我们再来看下观察者模式:

观察者模式

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<style>
			#title, #nav {
				font-size: 50px;
			}
		</style>
	</head>
	<body>
		<div id='title'>title:</div>
		<div id='nav'>nav:</div>
	</body>
	<script>
		// 定义目标对象(login)
		function Login(){
	      this.list = []
	      //[title,nva]
			};
	    // 添加订阅
	    Login.prototype.add = function (el){
	      this.list.push(el);
	    }
	    // 发布信息
	    Login.prototype.notice = function (){
	      this.list.forEach((el) => {	// 遍历执行该订阅事件下的函数
	        el.update()
	      });
	    }
	    let login = new Login();
	
	
	    // 定义观察者(element)
	    function Element(el) {
	      this.el = el
	    }
	    Element.prototype.update = function() {
	      document.getElementById(this.el).innerHTML = this.el + ':根据login拿到值了'
	    }
	    let title = new Element('title');
	    let nav = new Element('nav');
	
	    
	    // 观察者将自己订阅进目标对象里
	    login.add(title); 
	    login.add(nav);
	    // 用定时器模拟登录异步操作
	    setTimeout(() => {
	      login.notice();
	    }, 3000)
	</script>
</html>

我们可以看到,同一个应用场景,上面的代码也是可以实现,但相比发布-订阅模式不同的时,观察者模式并没有一个订阅中心,而是存在着一个目标对象(Login),而且观察者在订阅时,是将自己订阅进目标对象里的(login.add(title)),所以观察者和发布者之间还是存在的一定的联系,并不会像发布-订阅模式一样,完全分离。

总结

发布-订阅模式相比观察者模式,会多出来个订阅中心,作为发布者和订阅者之间的处理桥梁,这样的好处是使两者之间完全解耦,消除了发布者和订阅者之间的依赖。

三、发布-订阅模式关于Vue数据双向绑定原理的应用

前面说到,发布-订阅模式是我在学习Vue的数据双向绑定的原理时认识,所以这一小章节就来说一下发布-订阅模式关于Vue数据双向绑定原理的应用。由于篇幅问题,就另起文章写了:
https://blog.csdn.net/weixin_42436131/article/details/99546713

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值