前言

本系列文章主要根据《JavaScript设计模式与开发实践》整理而来,其中会加入了一些自己的思考。希望对大家有所帮助。

概念

发布—订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状 态发生改变时,所有依赖于它的对象都将得到通知。

场景

DOM事件



  document.body.addEventListener('click', function () {
alert(2);
}, false);
document.body.addEventListener('click', function () {
alert(3);
}, false);
document.body.addEventListener('click', function () {
alert(4);
}, false); document.body.click(); // 模拟用户点击

优缺点

优点:发布—订阅模式的优点非常明显,一为时间上的解耦,二为对象之间的解耦。
缺点:创建订阅者本身要消耗一定的时间和内存,而 且当你订阅一个消息后,也许此消息最后都未发生,但这个订阅者会始终存在于内存中。

例子

销售处订阅房源

简单的发布订阅



var Event = function() {
this.list = []
} Event.prototype.add = function(listener) {
this.list.push(listener)
} Event.prototype.triggle = function() {
this.list.forEach(listener => {
listener()
})
} var event = new Event()
event.add(()=>{console.log('房源1--80平--200万')})
event.add(()=>{console.log('房源2--200平--1000万')}) event.triggle()

或者



var event = {
list: [],
add(listener) {
this.list.push(listener)
},
triggle() {
this.list.forEach(listener => {
listener()
})
}
} event.add(()=>{console.log('房源1--80平--200万')})
event.add(()=>{console.log('房源2--200平--1000万')}) event.triggle()

但这种不能区分是发不了什么消息,比如有两群人:订阅80平房源报价和订阅200瓶房源报价的人,这里两群人都会得到通知

改进



var event = {
list: {},
add(type, listener) {
if (!this.list[type]) {
this.list[type] = []
}
this.list[type].push(listener)
},
triggle(type) {
this.list[type] && this.list[type].forEach(listener => {
listener()
})
}
} event.add('80平', ()=>{console.log('房源1--80平--200万')})
event.add('80平', ()=>{console.log('房源2--80平--300万')})
event.add('200平', ()=>{console.log('房源2--200平--1000万')}) event.triggle('80平')

这里还少了一个取消订阅的功能

增加取消订阅



var event = {
list: {},
add(type, listener) {
if (!this.list[type]) {
this.list[type] = []
}
this.list[type].push(listener)
},
triggle(type) {
this.list[type] && this.list[type].forEach(listener => {
listener()
})
},
remove(type, fn) {
if (!this.list[type]) return
var index = this.list[type].findIndex(listener => listener === fn)
this.list[type].splice(index, 1)
}
} var f1 = ()=>{console.log('房源1--80平--200万')}
var f2 = ()=>{console.log('房源2--80平--300万')}
var f3 = ()=>{console.log('房源2--200平--1000万')} event.add('80平', f1)
event.add('80平', f2)
event.add('200平', f3) event.remove('80平', f2)
event.triggle('80平') // 房源1--80平--200万

上面代码结构还不是很清晰,我们再模拟销售部真实的场景

更真实的销售部场景

  1. 销售部
  • 销售部有很多房源,如80平的,100平的等
  • 客户可以到销售部登记自己想买的房源面积,并留下姓名。到时候如果有房源,销售部就会通知客户
  • 客户由于一些原因决定不买房的时候,可以取消订阅
  1. 客户
  • 当有房源时,客户有一个接听报价的方法

var Event = function () {
this.list = {}
} Event.prototype.add = function (area, client) {
if (!this.list[area]) this.list[area] = []
this.list[area].push(client)
} Event.prototype.remove = function (area, client) {
if (!this.list[area]) return
var index = this.list[area].findIndex(item => item === client)
this.list[area].splice(index, 1)
} Event.prototype.triggle = function (area, price) {
if (!this.list[area]) return
this.list[area].forEach(client => {
client.listen(area, price)
})
} var Client = function (name) {
this.name = name
} Client.prototype.listen = function (area, price) {
console.log(`${this.name}收到${area}平的房源报价${price}`)
} var client1 = new Client('client1')
var client2 = new Client('client2') var event = new Event()
event.add('80平', client1)
event.add('100平', client1)
event.add('80平', client2)
event.add('300平', client1)
event.remove('300平', client1) event.triggle('80平', 200) // client1收到80平平的房源报价200 client2收到80平平的房源报价200
event.triggle('100平', 500) // client1收到100平平的房源报价500
event.triggle('200平', 1000) //
event.triggle('300平', 1000) //

上面的代码虽然已经很好了,但是还是有一个缺点:订阅者接收不到订阅之前发布的消息,如下客户3也想订阅80平的房源,但他收不到任何消息



var client3 = new Client('client3')
event.add('80平', client3)

我们希望客户3也能收到消息

必须先订阅再发布吗

我们增加一个cache字段来记录历史房源报价



var Event = function () {
this.list = {}
this.cache = {}
} Event.prototype.add = function (area, client) {
if (!this.list[area]) this.list[area] = []
this.list[area].push(client)
this.cache[area].forEach(price => {
client.listen(area, price)
})
} Event.prototype.remove = function (area, client) {
if (!this.list[area]) return
var index = this.list[area].findIndex(item => item === client)
this.list[area].splice(index, 1)
} Event.prototype.triggle = function (area, price) {
if (!this.cache[area]) this.cache[area] = []
this.cache[area].push(price) if (!this.list[area]) return
this.list[area].forEach(client => {
client.listen(area, price)
})
} var Client = function (name) {
this.name = name
} Client.prototype.listen = function (area, price) {
console.log(`${this.name}收到${area}平的房源报价${price}`)
} var client1 = new Client('client1')
var client2 = new Client('client2') var event = new Event()
// event.add('80平', client1)
// event.add('100平', client1)
// event.add('80平', client2)
// event.add('300平', client1)
// event.remove('300平', client1) event.triggle('80平', 200) // client1收到80平平的房源报价200 client2收到80平平的房源报价200
event.triggle('100平', 500) // client1收到100平平的房源报价500
event.triggle('200平', 1000) //
event.triggle('300平', 1000) // var client3 = new Client('client3')
event.add('80平', client3)
event.add('100平', client3)

网站登录

假如我们正在开发一个商城网站,网站里有 header 头部、nav 导航、消息列表、购物车等模块。这几个模块的渲染有一个共同的前提条件,就是必须先用 ajax 异步请求获取用户的登录信息。

这里留给读者自己实现

来源:https://segmentfault.com/a/1190000017758386

js设计模式--发布订阅模式的更多相关文章

  1. js设计模式-发布/订阅模式

    一.前言 发布订阅模式,基于一个主题/事件通道,希望接收通知的对象(称为subscriber)通过自定义事件订阅主题,被激活事件的对象(称为publisher)通过发布主题事件的方式被通知. 就和用户 ...

  2. [转]js设计模式—发布订阅模式

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

  3. JS的发布订阅模式

    JS的发布订阅模式 这里要说明一下什么是发布-订阅模式 发布-订阅模式里面包含了三个模块,发布者,订阅者和处理中心.这里处理中心相当于报刊办事大厅.发布者相当与某个杂志负责人,他来中心这注册一个的杂志 ...

  4. javascript设计模式——发布订阅模式

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

  5. 设计模式-发布订阅模式(javaScript)

    1. 前言 2. 什么是发布订阅模式 3. 发布订阅优缺点 4. 举例 4. 总结 1. 前言 发布订阅者模式是为了发布者和订阅者之间避免产生依赖关系,发布订阅者之间的订阅关系由一个中介列表来维护.发 ...

  6. javascript 设计模式 -- 发布/订阅模式

    直接上代码: index.html : <!DOCTYPE html> <html lang="en"> <head> <meta cha ...

  7. js 实现发布订阅模式

    /* Pubsub */ function Pubsub(){ //存放事件和对应的处理方法 this.handles = {}; } Pubsub.prototype = { //传入事件类型typ ...

  8. js 设计模式:观察者和发布订阅模式

    总是把这两个当作同一个模式,但其实是不太一样的,现在重温一下. 观察者模式 观察者直接订阅目标,当目标触发事件时,通知观察者进行更新 简单实现 class Observer { constructor ...

  9. JS设计模式(5)发布订阅模式

    什么是发布订阅模式(观察者模式)? 定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新. 主要解决:一个对象状态改变给其他对象通知的问题,而且 ...

随机推荐

  1. Vue 新手学习笔记:vue-element-admin 之安装,配置及入门开发

    所属专栏: Vue 开发学习进步 说实话都是逼出来的,对于前端没干过ES6都不会的人,vue视频也就看了基础的一些但没办法,接下来做微服务架构,前端就用 vue,这块你负责....说多了都是泪,脚手架 ...

  2. docker启动、关闭、重启命令

    docker启动命令,docker重启命令,docker关闭命令 启动        systemctl start docker守护进程重启   sudo systemctl daemon-relo ...

  3. docker Tomcat镜像

    docker中的管理命令 首先需要去下载镜像. [root@CFCA ~]# docker pull tomcat    下载镜像[root@CFCA ~]# docker images       ...

  4. Excel表格写入操作函数 C++

    #pragma once #include <stdio.h> #include <string.h> typedef unsigned short ushort; class ...

  5. 「CF803C」 Maximal GCD

    题目链接 戳我 \(Solution\) 令\(gcd\)为\(x\),那么我们将整个序列\(/x\),则序列的和就变成了\(\frac{n}{x}\),所以\(x\)必定为\(n\)的约数所以现在就 ...

  6. ast.literal_eval(转)

    eval函数在Python中做数据类型的转换还是很有用的.它的作用就是把数据还原成它本身或者是能够转化成的数据类型.那么eval和ast.literal_val()的区别是什么呢?本文将大家介绍关于P ...

  7. C++入门经典-类成员的可访问性,继承后的可访问性

    1:关键字public.private.protected说明类成员是共有的.私有的,还是保护的.这3个关键字将类划分为3个区域,在public区域的类成员可以在类作用域外被访问,而private区域 ...

  8. Leetcode题目21.合并两个有序链表(简单)

    题目描述: 将两个有序链表合并为一个新的有序链表并返回.新链表是通过拼接给定的两个链表的所有节点组成的. 示例: 输入:1->2->4, 1->3->4输出:1->1-& ...

  9. leetcode题目4.寻找两个有序数组的中位数(困难)

    题目描述: 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2. 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n)). 你可以假设 nums1 和  ...

  10. (五)C语言之表达式