无需原生开发基础,也能完美呈现京东商城。《混合开发京东商城系统,提前布局大前端》课程融合vue、Android、IOS等目前流行的前端和移动端技术,混合开发经典电商APP——京东。课程将各种复杂功能与知识点完美融合,从技术原理到开发上线,让你真实感受到一个明星产品开发的全过程。功能实现之外,还有一流用户体验和优秀交互设计等你一探究竟,拓宽开发眼界。
这一节我们来看 观察者模式 , 观察者模式 在面向前端的设计模式中是非常重要的一种设计模式,它在jQuery、Vue、React
包括原生JavaScript
语法中都有大量的应用。首先我们先来看 观察者模式 的定义。
观察者模式(发布订阅模式)就是:使用一个目标对象来管理所有依赖于它的观察者(订阅者)对象(一个或多个),并且在它本身的状态改变时主动向观察者(订阅者)对象发出通知。
我们用大白话来解释一下上面的定义,观察者模式它又被称为发布订阅模式,意思就是,在观察者模式中,它会存在一个发布者,和一个或者多个订阅者,发布者与订阅者是一种一对一或者一对多的关系。当发布者需要去更新状态的时候,它就会通知所有的订阅者,通过订阅者来完成状态的更新。
这就是 观察者模式(发布订阅模式) 的核心逻辑:当需要更新状态时,发布者会主动通知它的订阅者。那么大家可能会觉得,这样的一种模式他有什么作用呢?大家记住上面这句话,我们来看下面的实例。
举例说明
当我们肯德基吃饭的时候,我们去柜台点餐,点完餐之后,我们拿到一个编号,就可以去座位上等着,这时候我们可以看手机,干什么都行,等到点的餐弄好了之后,营业员会叫我们的编号,我们根据手中的编号直接去柜台领餐就可以。
这样的一种方式,其实就是观察者模式(发布订阅模式) ,我们再来回顾一下它的核心逻辑:当需要更新状态时,发布者会主动通知它的订阅者。在我们上面的事例中,更新状态就是我们点的餐被制作完成了,这时候状态发生了变化,然后发布者就是肯德基的营业员,我们就是这个营业员的订阅者,我们手中的编号就是发布者用来确定我们身份的订阅者编号,营业员通知我们订的餐被制作完成,我们根据手中的编号来去取出汉堡。这就是活生生的 观察者模式(发布订阅模式) , 当需要更新状态时,发布者会主动通知它的订阅者 。
OK,然后我们接下来就来绘制一下 观察者模式(发布订阅模式) 的UML类图
。
绘制UML类图
我们看上图中绘制的UML类图
,在上图中我们通过Observer
表示我们的订阅者,即事例中的客户,Subject
表示发布者,即事例中的肯德基商家。所有的订阅者都有一个自己的标记code
,并且持有发布者的引用,订阅者提供了一个update
的方法,当该方法被调用时,表示订阅者状态更新。而发布者则持有了订阅者的集合,即observers
,并且发布者有一个自己的名字name
,同时它提供了两个方法,当有新的订阅者被添加到observers
的时候,会调用addObserver
, 而当调用notifyAllObservers
的时候,表示发布者通知所有的订阅者状态需要更新了。
oK,前端中的UML类图
设计总是会比较简单。然后我们来看一下代码实现。
代码实现
class Subject {
constructor () {
this.observers = [];
this.name = '发布者';
}
addObserver (observer) {
this.observers.push(observer);
}
notifyAllObservers () {
this.observers.forEach(observer => {
observer.update();
});
}
}
class Observer {
constructor (code, subject) {
this.code = code;
this.subject = subject;
this.subject.addObserver(this);
}
update () {
console.log(`${this.subject.name}通知订阅者${this.code}更新`);
}
}
如代码所示,我们首先创建了发布者Subject
,并为他创建了两个方法addObserver 和 notifyAllObservers
,分别用来添加订阅者和更新订阅者状态。然后创建了订阅者Observer
,订阅者中保存一个编号code
,同时持有了它的发布者对象subject
,并为subject
添加了订阅者也就是它自己在this.subject.addObserver(this);
,然后创建了一个update
方法,表示状态更新。
然后我们就需要分别创建发布者和订阅者,如下面代码所示:
const subject = new Subject();
const o1 = new Observer('1', subject);
const o2 = new Observer('2', subject);
const o3 = new Observer('3', subject);
subject.notifyAllObservers();
我们分别创建了subject
和observer
,然后通过notifyAllObservers
,来通知所有的订阅者更新状态。
最后的打印结果如下:
发布者通知订阅者1更新
发布者通知订阅者2更新
发布者通知订阅者3更新
到这里,大家应该已经对什么是 观察者模式(发布订阅模式) 有了一个完整的认识了吧。然后我们就来看一下 观察者模式(发布订阅模式) 的使用场景。
使用场景
观察者模式在前端中的使用场景非常的多,比如Vue
中的响应式数据渲染机制也都是通过 观察者模式(发布订阅模式) 来实现的,这一块内容我在另外一本书 深入浅出学习Vue开发 中做了详细的演示,并且通过 观察者模式(发布订阅模式) 实现了一个响应式的框架。这一块的内容整体比较负责,我们本书主要目的是讲解设计模式,所以就不去采用这么复杂的事例了,如果大家对 响应式数据渲染 这一块内容感兴趣的,可以看一下我的这本书 深入浅出学习Vue开发 。
我们在这里准备了两个事例,第一个是js
中的事件绑定机制。
div.click = function () {
alert('onclick');
}
js
中的事件绑定我们基本上天天都在写,但是可能很少有人知道这是使用了 观察者模式(发布订阅模式) 来实现的。那么在这一段代码里面,谁是发布者,谁是订阅者?我们再来回顾一下 观察者模式(发布订阅模式) 的定义:当需要更新状态时,发布者会主动通知它的订阅者 。当我们执行了上面的这段代码之后,alert('onclick');
,他并不会立刻执行,它什么时候执行取决于我们什么时候去点击这个div
,触发div
的click
事件。
OK,那么我们把它换成 观察者模式(发布订阅模式) 的语法来解释一下就是,订阅者alert('onclick');
会在接收到发布者div.click
的通知的时候才回去执行。对吧 , 这就是一个标准的 观察者模式(发布订阅模式) 机制。
然后第二个事例,我们来看Promise
,Promise
是我们比较常用的一种异步编程的解决方案,而它的实现也是使用了 观察者模式(发布订阅模式) 。我们一起来看一下。
function createPromise (src) {
return new Promise ((resolve, reject) => {
const img = document.createElement('img');
img.onload = () => {
resolve(img);
}
img.onerror = () => {
reject(img);
}
img.src = src;
document.body.appendChild(img);
});
}
看上面的代码,我们通过createPromise
方法创建并返回了一个Promise
对象,我们利用这个Promise
创建了一个img
标签并为它设置了图片地址,当图片加载成功的时候,回调resolve
,当图片加载失败的时候,回调reject
。
然后我们就可以通过Promise
对象的then
方法来响应Promise
的状态变化
const src = 'https://images.gitbook.cn/logo.png';
const promise = createPromise(src);
promise.then(() => {
console.log('图片加载完成');
}).catch(() => {
console.log('图片加载失败');
});
总结
我们本章学习的是 观察者模式 ,观察者模式又被成为发布订阅模式 , 原因就是因为在 观察者模式 中总会使用一个目标对象(发布者)来管理所有依赖于它的观察者(订阅者)对象(一个或多个)。
在我们的前端开发中 观察者模式(发布订阅模式) 的使用是非常广泛的,我们上面列出的例子也只是冰山一角。另外如果大家想要学习好设计模式的话,那么一定要记住我们在第一章所说的,设计与模式是分开的两个概念,我们可以把设计当成一种理念,模式则是使理念具现化的一种格式,对于我们的学习一定要,重设计轻模式,掌握理念而不是拘泥于形式。