什么是观察者模式

观察者模式

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个目标对象,当这个目标对象的状态发生变化时,会通知所有观察者对象,使它们能够自动更新。 —— 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 设计模式之观察者模式相关推荐

  1. JavaScript设计模式之观察者模式(学习笔记)

    设计模式(Design Pattern)对于软件开发来说其重要性不言而喻,代码可复用.可维护.可扩展一直都是软件工程中的追求!对于我一个学javascript的人来说,理解设计模式似乎有些困难,对仅切 ...

  2. JavaScript 设计模式之观察者模式与发布订阅模式

    前言 在软体工程中,设计模式(design pattern)是对软体设计中普遍存在(反复出现)的各种问题,所提出的解决方案. 设计模式并不直接用来完成程式码的编写,而是描述在各种不同情况下,要怎么解决 ...

  3. javascript设计模式之观察者模式

    dom 的事件模式就是观察者模式 /** 观察者模式又叫发布者-订阅者模式* 我发布一则消息,消息就在那里:你若订阅,我便发送. *//** js和dom之间的实现就是一种观察者模式:* 所有的dom ...

  4. 【JavaScript设计模式】观察者模式

    观察者模式 文章目录 观察者模式

  5. JavaScript设计模式:观察者模式与发布订阅者模式实现

    观察者模式 当对象之间存在一对多的依赖关系时,其中一个对象的状态发生改变,所有依赖它的对象都会收到通知,这就是观察者模式. 在观察者模式中,只有两种主体:目标对象 (Subject) 和 观察者 (O ...

  6. 【JavaScript设计模式】-观察者模式 Observe

    关系介绍 为方便记忆我将真个模式主要分为三个部分: 发布者:在执行某个动作后将特定的消息发布到消息池 订阅者:将订阅的特定消息注册到消息池,并提交一个回调函数,在订阅的消息被触发时,会执行该回调函数, ...

  7. 《JavaScript设计模式与开发实践》模式篇(5)—— 观察者模式

    发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状 态发生改变时,所有依赖于它的对象都将得到通知.在 JavaScript 开发中,我们一般用事件模型 来替代传统的发布- ...

  8. JavaScript设计模式之发布-订阅模式(观察者模式)-Part1

    <JavaScript设计模式与开发实践>读书笔记. 发布-订阅模式又叫观察者模式,它定义了对象之间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖它的对象都将得到通知. 例如 ...

  9. 16种JavaScript设计模式(中)

    简介 上文中介绍了学习设计模式前需要了解的一些基础概念和js的基础模式-原型模式,没看过的同学可以点这里,本章将介绍以下几种模式 单例模式 策略模式 代理模式 迭代器模式 发布订阅模式 命令模式 组合 ...

最新文章

  1. 电子时钟单片机c语言程序,51单片机电子时钟C语言程序
  2. python-水仙花数
  3. 20十年后的计算机作文600字,20年后的学校作文600字
  4. 知识图谱(知识图谱构建)
  5. vue keep-alive保存路由状态2 (高级用法,接上篇)
  6. 一款超炫的图片排列特效
  7. 工作总结11:vue获取数据接口
  8. 关于android LinearLayout的比例布局(转载)
  9. mysql in从数据库取数_MySQL数据库中 where in 用法详解
  10. app流量相对专项测试(待续)
  11. Centos7下载linux内核源码
  12. bootbox.js——弹框插件
  13. 羊群效应?redis解决方案
  14. 你很牛,且是刚毕业的,那就到华为上班吧!--绝对隐私:华为员工待遇全面揭秘
  15. oracle adf源代码在哪里,第 3 章 | 从设计到实践全面了解 Oracle ADF 应用程序
  16. 英文Essay写作中存在哪些门道?
  17. 计算机考研基本信息,复旦大学计算机考研基本信息
  18. MFC ActiveX控件的3种调用方式
  19. 对1976年Diffie和Hellman的文章《New Direction in Cryptography》的中文翻译
  20. c++:vector sort()排序

热门文章

  1. 【Web技术】1016- 全面理解 8 种文件上传场景
  2. java 多线程开发
  3. 牛客网 http://www.nowcoder.com/test/question/done?tid=2198842qid=14753#summary
  4. 使用uniapp 开发微信小程序map组件在开发过程中遇到的问题
  5. 编写一个程序,计算 1 + 2 + 3 + 4 + … + 100 的累加和,并把累加和以 2 进制形式显示出来(要使 用循环累加方法,不能使用公式 S=N*(N+1)/2=50*101=5050)
  6. js、vue、手机号、身份证号、姓名脱敏
  7. 作用域(全局作用域和函数作用域)
  8. 时间格式化(XXXX年-XX月-XX日 XX:XX:XX)
  9. 网页禁止复制粘贴怎么办?教你六招轻松完成
  10. 有关全基因组测序的文献复现