javascript 设计模式之观察者模式
什么是观察者模式
观察者模式
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个目标对象,当这个目标对象的状态发生变化时,会通知所有观察者对象,使它们能够自动更新。 —— Graphic Design Patterns
生活中的观察者模式
小明最近看中了一个楼盘,到了售楼处之后才被告知,该楼盘的房子还未开盘,具体开盘时间还没定。除了小明,一起来的还有小红,小二人,为了第一时间得知楼盘开盘时间,他们都把电话号码留给了销售员王五,王五也答应楼盘一开盘就会发消息通知他们。
过了不久,新楼盘开盘时间定了,王五赶紧拿出花名册,遍历上面的号码,群发了短信通知了他们。
至于这些人收到通知是选择走路来、开车来、或者不来就自行决定了
重点概念对号入座
观察者模式有个"别名",叫发布-订阅模式(两者还是有些不一样,会另外有文章介绍)。这个别名非常形象诠释了观察者模式里的两个核心的角色要求:发布者与订阅者。将生活中的这个案例对号入座如下:
发布者: 王五
订阅者: 小明、小红,小二
订阅事件: 小明、小红、小二将号码留在售楼部
发布事件: 王五群发短信通知他们
自定义观察者模式
经过上面的分析,该模式要创建两个类,一个是代表发布者,起名 Publisher,另一个是代表订阅者,起名 Observer 。
这个类应该要有哪些功能呢?大家看下上文中的王五有什么操作?
- 登记小明、小红、小二的号码(增加订阅者)
- 群发短信通过小明、小红、小二(通知订阅者)
- 另外作为销售员,还应该具有删除某些人的权限吧(比如小明答复说已经不买了,那这时就可以考虑将他从花名册去删除)
根据上面的分析,写出如下代码:
// 定义发布者类
class Publisher {constructor() {this.observers = []console.log('Publisher created')}// 增加订阅者add(observer) {console.log('Publisher.add invoked')this.observers.push(observer)}// 移除订阅者remove(observer) {console.log('Publisher.remove invoked')this.observers.forEach((item, i) => {if (item === observer) {this.observers.splice(i, 1)}})}// 通知所有订阅者notify() {console.log('Publisher.notify invoked')this.observers.forEach((observer) => {observer.update(this)})}
}
再来看下订阅者具备的功能,小明有啥能力呢?
- 被通知楼盘开盘
// 定义订阅者类
class Observer {constructor() {console.log('Observer created')}update() {console.log('Observer.update invoked')}
}
上面定义的就是最基本的观察者模式的两个类(面试时如果有被问到自定义个基本的观察者模式,就可以将上面的代码输出)。在实际的业务开发中,定制化的发布者/订阅者都可以继承这两个基本来扩展。比如现在有个需求是监听楼盘开盘与否的变化。代码如下:
// 定义个具体的销售员发布类
class SalesPublisher extends Publisher {constructor() {super()// 楼盘起初是还未开盘this.state = 'close'// 还没将人员号码登记this.observers = []}// 获取当前楼盘状态getState() {return this.state}// 设置楼盘状态setState(state) {console.info('楼盘开盘了')this.state = state// 楼盘状态一改, 通知要购买房子的人this.notify()}
}
作为购房者
// 购房子类
class BuyerObserver extends Observer {constructor(name) {super()this.name = name}// 重写一个具体的 update 方法update(publisher) {// 获取楼盘的状态let state = publisher.getState()console.info(`${this.name} update, state: ${state}`)this.doSomething()}// 接收到消息之后,后续要处理的逻辑,比如回复销售员收到,开始筹钱等等doSomething() {console.info('开始筹钱')}
}
下面,让我们来检验下该代码是否能够正常?
何为正常:就是当楼盘状态更改时,都会紧接着调用 notify 方法来通知所有购房者,也就实现了定义里所谓的:
目标对象的状态发生变化时,会通知所有观察者对象,使它们能够自动更新。
// 创建订阅者: 小明
const xiaoMing = new BuyerObserver('小明')
// 创建订阅者: 小红
const xiaoHong = new BuyerObserver('小红')
// 创建订阅者: 小二
const xiaoEr = new BuyerObserver('小二')// 创建发布者: 王五
const wangwu = new SalesPublisher()// 开始添加购房者的号码
wangwu.add(xiaoMing)
wangwu.add(xiaoHong)
wangwu.add(xiaoEr)// 楼盘开盘了,是时候通知购房者了
wangwu.setState('open')
以上,就是一个观察者模式实现过程
观察者模式使用场景
vue 的双向绑定
Object.defineProperty
使用 Object.defineProperty(obj, props, descriptor) 实现观察者模式, 其也是 vue 双向绑定 的核心
示例如下(当改变 obj 中的 value 的时候, 自动调用相应相关函数):
var obj = {data: { list: [] },
}Object.defineProperty(obj, 'list', {get() {return this.data['list']},set(val) {console.log('值被更改了')this.data['list'] = val}
})
Proxy
Proxy/Reflect 是 ES6 引入的新特性, 也可以使用其完成观察者模式
var obj = {value: 0
}var proxy = new Proxy(obj, {set: function(target, key, value, receiver) { // {value: 0} "value" 1 Proxy {value: 0}console.log('调用相应函数')Reflect.set(target, key, value, receiver)}
})proxy.value = 1 // 调用相应函数
参考链接
JavaScript 设计模式核⼼原理与应⽤实践
结语
现在,是不是对观察者模式有了比较深刻的理解呢?其实观察者模式在工作中还是用的挺多的,像是上面提到的事件监听,实际上我们经常写到,只是不知道它就是观察者模式。下一篇将会讲到发布-订阅者模式,这两种是有根本区别的,敬请期待。
你的点赞是对我最大的肯定,如果觉得有帮助,请留下你的赞赏,谢谢!!!
本文代码
javascript 设计模式之观察者模式相关推荐
- JavaScript设计模式之观察者模式(学习笔记)
设计模式(Design Pattern)对于软件开发来说其重要性不言而喻,代码可复用.可维护.可扩展一直都是软件工程中的追求!对于我一个学javascript的人来说,理解设计模式似乎有些困难,对仅切 ...
- JavaScript 设计模式之观察者模式与发布订阅模式
前言 在软体工程中,设计模式(design pattern)是对软体设计中普遍存在(反复出现)的各种问题,所提出的解决方案. 设计模式并不直接用来完成程式码的编写,而是描述在各种不同情况下,要怎么解决 ...
- javascript设计模式之观察者模式
dom 的事件模式就是观察者模式 /** 观察者模式又叫发布者-订阅者模式* 我发布一则消息,消息就在那里:你若订阅,我便发送. *//** js和dom之间的实现就是一种观察者模式:* 所有的dom ...
- 【JavaScript设计模式】观察者模式
观察者模式 文章目录 观察者模式
- JavaScript设计模式:观察者模式与发布订阅者模式实现
观察者模式 当对象之间存在一对多的依赖关系时,其中一个对象的状态发生改变,所有依赖它的对象都会收到通知,这就是观察者模式. 在观察者模式中,只有两种主体:目标对象 (Subject) 和 观察者 (O ...
- 【JavaScript设计模式】-观察者模式 Observe
关系介绍 为方便记忆我将真个模式主要分为三个部分: 发布者:在执行某个动作后将特定的消息发布到消息池 订阅者:将订阅的特定消息注册到消息池,并提交一个回调函数,在订阅的消息被触发时,会执行该回调函数, ...
- 《JavaScript设计模式与开发实践》模式篇(5)—— 观察者模式
发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状 态发生改变时,所有依赖于它的对象都将得到通知.在 JavaScript 开发中,我们一般用事件模型 来替代传统的发布- ...
- JavaScript设计模式之发布-订阅模式(观察者模式)-Part1
<JavaScript设计模式与开发实践>读书笔记. 发布-订阅模式又叫观察者模式,它定义了对象之间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖它的对象都将得到通知. 例如 ...
- 16种JavaScript设计模式(中)
简介 上文中介绍了学习设计模式前需要了解的一些基础概念和js的基础模式-原型模式,没看过的同学可以点这里,本章将介绍以下几种模式 单例模式 策略模式 代理模式 迭代器模式 发布订阅模式 命令模式 组合 ...
最新文章
- 电子时钟单片机c语言程序,51单片机电子时钟C语言程序
- python-水仙花数
- 20十年后的计算机作文600字,20年后的学校作文600字
- 知识图谱(知识图谱构建)
- vue keep-alive保存路由状态2 (高级用法,接上篇)
- 一款超炫的图片排列特效
- 工作总结11:vue获取数据接口
- 关于android LinearLayout的比例布局(转载)
- mysql in从数据库取数_MySQL数据库中 where in 用法详解
- app流量相对专项测试(待续)
- Centos7下载linux内核源码
- bootbox.js——弹框插件
- 羊群效应?redis解决方案
- 你很牛,且是刚毕业的,那就到华为上班吧!--绝对隐私:华为员工待遇全面揭秘
- oracle adf源代码在哪里,第 3 章 | 从设计到实践全面了解 Oracle ADF 应用程序
- 英文Essay写作中存在哪些门道?
- 计算机考研基本信息,复旦大学计算机考研基本信息
- MFC ActiveX控件的3种调用方式
- 对1976年Diffie和Hellman的文章《New Direction in Cryptography》的中文翻译
- c++:vector sort()排序
热门文章
- 【Web技术】1016- 全面理解 8 种文件上传场景
- java 多线程开发
- 牛客网 http://www.nowcoder.com/test/question/done?tid=2198842qid=14753#summary
- 使用uniapp 开发微信小程序map组件在开发过程中遇到的问题
- 编写一个程序,计算 1 + 2 + 3 + 4 + … + 100 的累加和,并把累加和以 2 进制形式显示出来(要使 用循环累加方法,不能使用公式 S=N*(N+1)/2=50*101=5050)
- js、vue、手机号、身份证号、姓名脱敏
- 作用域(全局作用域和函数作用域)
- 时间格式化(XXXX年-XX月-XX日 XX:XX:XX)
- 网页禁止复制粘贴怎么办?教你六招轻松完成
- 有关全基因组测序的文献复现