js设计模式之发布订阅模式
1. 定义
发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。
订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Event Channel),当发布者(Publisher)发布该事件(Publish Event)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。
2 发布订阅模式的图解以及与观察者模式之间的差异和类似之处:
3 实现发布订阅模式的 相关思路:
- 创建一个对象
- 在该对象上创建一个缓存列表(调度中心)
- on 方法用来把函数 fn 都加到缓存列表中(订阅者注册事件到调度中心)
- emit 方法取到 arguments 里第一个当做 event,根据 event 值去执行对应缓存列表中的函数(发布者发布事件到调度中心,调度中心处理代码)
- off 方法可以根据 event 值取消订阅(取消订阅)
- once 方法只监听一次,调用完毕后删除缓存函数(订阅一次)
eg1:简单一点的demo:
// 定义一个对象作为调度中心,或者一个类。
let eventEmitter = {}; // 缓存列表,存放 event 及 fn
eventEmitter.list = {}; // 订阅
eventEmitter.on = function (event, fn) {
let _this = this;
// 如果对象中没有对应的 event 值,也就是说明没有订阅过,就给 event 创建个缓存列表
// 如有对象中有相应的 event 值,把 fn 添加到对应 event 的缓存列表里
(_this.list[event] || (_this.list[event] = [])).push(fn);
return _this;
}; // 发布
eventEmitter.emit = function () {
let _this = this;
// 第一个参数是对应的 event 值,直接用数组的 shift 方法取出
let event = [].shift.call(arguments), // 删除并拿到arguments
的第一项 详细参考:https://blog.csdn.net/u013946061/article/details/108269650博客。
fns = [..._this.list[event]];
// 如果缓存列表里没有 fn 就返回 false
if (!fns || fns.length === 0) {
return false;
}
// 遍历 event 值对应的缓存列表,依次执行 fn
fns.forEach(fn => {
fn.apply(_this, arguments);
});
return _this;
}; function user1 (content) {
console.log('用户1订阅了:', content);
}; function user2 (content) {
console.log('用户2订阅了:', content);
}; // 订阅
eventEmitter.on('article', user1);
eventEmitter.on('article', user2); // 发布
eventEmitter.emit('article', 'Javascript 发布-订阅模式'); /*
用户1订阅了: Javascript 发布-订阅模式
用户2订阅了: Javascript 发布-订阅模式
*/e
eg2: 实现一次订阅的once方法和取消订阅的off方法:
let eventEmitter = {
// 缓存列表
list: {},
// 订阅
on (event, fn) {
let _this = this;
// 如果对象中没有对应的 event 值,也就是说明没有订阅过,就给 event 创建个缓存列表
// 如有对象中有相应的 event 值,把 fn 添加到对应 event 的缓存列表里
(_this.list[event] || (_this.list[event] = [])).push(fn);
return _this;
},
// 监听一次 并且只执行一次 之后取消订阅
once (event, fn) {
// 先绑定,调用后删除
let _this = this;
function on () {
_this.off(event, on); //取消订阅
fn.apply(_this, arguments); // 执行fn函数
}
on.fn = fn;
_this.on(event, on);
return _this;
},
// 取消订阅
off (event, fn) {
let _this = this;
let fns = _this.list[event];
// 如果缓存列表中没有相应的 fn,返回false
if (!fns) return false;
if (!fn) {
// 如果没有传 fn 的话,就会将 event 值对应缓存列表中的 fn 都清空
fns && (fns.length = 0);
} else {
// 若有 fn,遍历缓存列表,看看传入的 fn 与哪个函数相同,如果相同就直接从缓存列表中删掉即可
let cb;
for (let i = 0, cbLen = fns.length; i < cbLen; i++) {
cb = fns[i];
if (cb === fn || cb.fn === fn) {
fns.splice(i, 1);
break
}
}
}
return _this;
},
// 发布
emit () {
let _this = this;
// 第一个参数是对应的 event 值,直接用数组的 shift 方法取出
let event = [].shift.call(arguments),
fns = [..._this.list[event]];
// 如果缓存列表里没有 fn 就返回 false
if (!fns || fns.length === 0) {
return false;
}
// 遍历 event 值对应的缓存列表,依次执行 fn
fns.forEach(fn => {
fn.apply(_this, arguments);
});
return _this;
}
}; function user1 (content) {
console.log('用户1订阅了:', content);
} function user2 (content) {
console.log('用户2订阅了:', content);
} function user3 (content) {
console.log('用户3订阅了:', content);
} function user4 (content) {
console.log('用户4订阅了:', content);
} // 订阅
eventEmitter.on('article1', user1);
eventEmitter.on('article1', user2);
eventEmitter.on('article1', user3); // 取消user2方法的订阅
eventEmitter.off('article1', user2); eventEmitter.once('article2', user4) // 发布
eventEmitter.emit('article1', 'Javascript 发布-订阅模式');
eventEmitter.emit('article1', 'Javascript 发布-订阅模式');
eventEmitter.emit('article2', 'Javascript 观察者模式');
eventEmitter.emit('article2', 'Javascript 观察者模式'); // eventEmitter.on('article1', user3).emit('article1', 'test111'); /*
用户1订阅了: Javascript 发布-订阅模式
用户3订阅了: Javascript 发布-订阅模式
用户1订阅了: Javascript 发布-订阅模式
用户3订阅了: Javascript 发布-订阅模式
用户4订阅了: Javascript 观察者模式
*/
1 优点:
- 对象之间解耦
- 异步编程中,可以更松耦合的代码编写
2 不足之处:
- 创建订阅者本身要消耗一定的时间和内存
- 虽然可以弱化对象之间的联系,多个发布者和订阅者嵌套一起的时候,程序难以跟踪维护
观察者模式和发布订阅模式之间的区别和异同:
观察者模式
:观察者(Observer)直接订阅(Subscribe)主题(Subject),而当主题被激活的时候,会触发(Fire Event)观察者里的事件。
发布订阅模式
:订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Event Channel),当发布者(Publisher)发布该事件(Publish Event)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。
差异:
- 在观察者模式中,观察者是知道 Subject 的,Subject 一直保持对观察者进行记录。然而,在发布订阅模式中,发布者和订阅者不知道对方的存在。它们只有通过消息代理进行通信。
- 在发布订阅模式中,组件是松散耦合的,正好和观察者模式相反。
- 观察者模式大多数时候是同步的,比如当事件触发,Subject 就会去调用观察者的方法。而发布-订阅模式大多数时候是异步的(使用消息队列)。
- 观察者模式需要在单个应用程序地址空间中实现,而发布-订阅更像交叉应用模式。
js设计模式之发布订阅模式的更多相关文章
- js设计模式之发布/订阅模式模式
一.前言 发布订阅模式,基于一个主题/事件通道,希望接收通知的对象(称为subscriber)通过自定义事件订阅主题,被激活事件的对象(称为publisher)通过发布主题事件的方式被通知. 就和用户 ...
- 浅谈js设计模式之发布 — 订阅模式
发布 — 订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知.在 JavaScript开发中,我们一般用事件模型来替代传统的发布 — ...
- [转] JavaScript设计模式之发布-订阅模式(观察者模式)-Part1
<JavaScript设计模式与开发实践>读书笔记. 发布-订阅模式又叫观察者模式,它定义了对象之间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖它的对象都将得到通知. 例如 ...
- JS 设计模式八 -- 发布订阅者模式
概念 发布---订阅模式又叫观察者模式,它定义了对象间的一种一对多(一个发布,多个观察)的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知. 优点 1 ...
- JS中的发布订阅模式
一. 你是如何理解发布订阅模式的 JS中的设计模式: 单例模式:处理业务逻辑 构造原型模式:封装类库,组件,框架,插件等 类库:jQuery 只是提供了一些常用的方法,可以应用到任何的项目中,不具备业 ...
- JavaScript设计模式(发布订阅模式)
发布—订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知.在JavaScript开发中,我们一般用事件模型来替代传统的发布—订阅模式 ...
- Javascript设计模式之发布-订阅模式
简介 发布-订阅模式又叫做观察者模式,他定义了一种一对多的依赖关系,即当一个对象的状态发生改变的时候,所有依赖他的对象都会得到通知. 回忆曾经 作为一名前端开发人员,给DOM节点绑定事件可是再频繁不过 ...
- javascript中的设计模式之发布-订阅模式
一.定义 又叫观察者模式,他定义对象间的依照那个一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将的到通知.在javascript中,我们一般用时间模型来替代传统的发布-订阅模式 二 ...
- js里的发布订阅模式及vue里的事件订阅实现
发布订阅模式(观察者模式) 发布订阅模式的定义:它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. 发布订阅模式在JS中最常见的就是DOM的事件绑定与触发 ...
随机推荐
- Linux连接工具final配置
Linux连接工具 putty .CRT.XShell 在terminal里面敲不太方便,所以需要一款连接工具 这是一款美观医用的网络服务管理软件 安装final shell Windows版下载地址 ...
- Redis-02-主从复制和哨兵模式
安全认证 开启认证 redis默认开启了保护模式,只允许本地回环地址登录并访问数据库 修改redis的配置文件,并重启redis的服务 vim /opt/redis_cluster/redis_637 ...
- Mysql报错注入之floor报错详解
一.简述 利用 select count(*),(floor(rand(0)*2))x from table group by x,导致数据库报错,通过 concat 函数,连接注入语句与 floor ...
- 支持初始化数据的Zookeeper Docker镜像
最近在做一个演示项目 https://github.com/cnscud/cavedemo, 自然为了方便, 也做了docker打包, 发现zookeeper的镜像没有导入初始化数据的功能, 于是自己 ...
- NOIP 模拟 $17\; \rm 世界线$
题解 \(by\;zj\varphi\) 此题经简单观察可发现,一个点的贡献就是这个点所能到的点减去它的出度 那么我们就可以暴力搜索,但是显然会超时,所以我们可以使用一个黑科技 \(\rm bitse ...
- 题解—P2898 [USACO08JAN]Haybale Guessing G
pre 首先注意一下翻译里面并没有提到的一点,也是让我没看懂样例的一点,就是这个长度为 \(n\) 的数组里面的数各不相同. 有很多人用并查集写的这道题,题解里面也有一些用线段树写的,不过我认为我的做 ...
- 熟悉而陌生的新朋友——IAsyncDisposable
本文作者--句幽 在.NET Core 3.0的版本更新中,官方我们带来了一个新的接口 IAsyncDisposable. 小伙伴一看肯定就知道,它和.NET中原有的IDisposable接口肯定有着 ...
- mysql几种连接方式区别
mysql的几种join 2017年03月19日 14:49:07 carl-zhao 阅读数:7845 标签: mysqlsqljoin 更多 个人分类: MySQL 版权声明:本文为博主原创文章, ...
- sql查询第10条到第20条数据
select top(10) * from T1 where Id >= (select MAX(Id) from (select top(20) * from T1 order by Id) ...
- vue引入zTree入门
参考1:https://blog.csdn.net/tg928600774/article/details/80911589 参考2:https://blog.csdn.net/ylhsuper/ar ...