前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >TS 设计模式08 - 发布订阅模式

TS 设计模式08 - 发布订阅模式

作者头像
love丁酥酥
发布于 2020-09-19 05:55:28
发布于 2020-09-19 05:55:28
1.1K00
代码可运行
举报
文章被收录于专栏:coding for lovecoding for love
运行总次数:0
代码可运行

1. 简介

前面介绍了观察者模式,就好比我们去点餐,通知服务员说,餐好了跟我说一下。那么服务员和顾客之间就形成了耦合,首先服务员得知道餐品好了以后通知那些顾客,其次,如果是多位服务员协作,每个服务员都需要知道这些顾客。

但事实上你发现去 kfc 点餐的时候,服务员并没有直接通知我们。而是采用叫号的方式。细想一下,你去 kfc,是不是可以在点餐系统进行排号(网上或者排队,这里抽象一下),餐品好了以后,服务员输入点餐号,点一下完成即可,点餐系统会通知对应的顾客取餐。

这里你和服务员之间的消息通过点餐系统来传递,你并不需要知道是谁点的完成,服务员也不需要知道这份餐品给谁。完美解耦了消息的发送者和接收者。更好地是,我们在点餐或者叫号的时候其实还可以指定行为,比如说 66 号产品好了以后帮我送到 A1 桌。

再比如说炒股的时候,我们可以委托挂单,就是当股票到了某一个价格就帮你买入或者卖出,等等,例子很多。

2. 用例图

3. 实现

node 中 EventEmitter 就是这样一个典型例子。我们来简单实现一个 EventEmitter。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface HandlerInfo {
    handler: Function;
    once?: boolean;
}
class EventEmitter {
    private events: Map<string, HandlerInfo[]> = new Map();
    on(type: string, handler: Function, once?: boolean) {
        if (!this.events.has(type)) {
            this.events.set(type, []);
        }
        (this.events.get(type) || []).push({
            handler,
            once,
        });
        return () => {
            this.off(type, handler);
        };
    }
    once(type: string, handler: Function) {
        return this.on(type, handler, true);
    }
    emit(type: string, ...args) {
        let i = 0;
        while (i < (this.events.get(type) || []).length) { // 这里每次都从 this.events 去动态读取,方中途被变更
            const handlers: HandlerInfo[] = this.events.get(type) || [];
            const { handler, once } = handlers[i];
            // 如果是一次性的,应该在调用前删除,防止这里会自己触发自己,导致无限循环或者次序错乱
            if (once) {
                handlers.splice(i--, 1);
            }
            i++;
            handler(...args); // 这里 this 就交给传入的 handler 来保证了
        }
    }
    off(type?: string, handler?: Function): void {
        if (!type) return; // 最好不要默认全部清除,不安全
        if (!handler) {
            this.events.set(type, []); // 因为这里是直接赋值清空,所以在 emit 的时候,记得每次都从 events 动态获取
            return;
        }
        this.events.set(type, (this.events.get(type) || []).filter(item => item.handler !== handler));
    }
}

const eventEmitter = new EventEmitter();

class Person {
    public name: string;
    constructor(name: string) {
        this.name = name;
    }
    weatherSubscribe(once?: boolean): Function {
        return eventEmitter.on('weather', (weather) => {
            switch (weather) {
                case '雨':
                    console.log(`${this.name}在家看电影`);
                    break;
                default:
                    console.log(`${this.name}出去玩`);
            }
        }, once);
    }
    weatherNotify(weather) {
        eventEmitter.emit('weather', weather);
    }
}

const xiaoWang = new Person('小王');
const xiaoMing = new Person('小明');
const xiaoZhang = new Person('小张');

xiaoWang.weatherSubscribe(true);
const off = xiaoMing.weatherSubscribe();

xiaoZhang.weatherNotify('雨');
xiaoZhang.weatherNotify('晴');

off();
xiaoZhang.weatherNotify('晴');

4. 小结

发布订阅模式可以说是对观察者模式的进一步抽象。

我们通过消息中心对消息进行统一处理,那么这里通知者和消费者的关系其实被弱化了,它们可以是任意对象,通知者和消费者也可以是同一个对象,这种模式甚至在非对象也可以使用,即我们只关注发布和订阅行为本身,而不关心发布订阅者是谁。

参考

从发布订阅模式入手读懂Node.js的EventEmitter源码 使用typescript 写一个简单的事件监听/发布订阅模式的类 TypeScript 设计模式之发布-订阅模式 观察者模式和发布订阅模式的区别 图解23种设计模式(TypeScript版)——前端必修内功心法 观察者模式 vs 发布订阅模式 设计模式之发布订阅模式(1) 一文搞懂发布订阅模式 github - node/lib/events github - wxpage/lib/message Node中EventEmitter理解与简单实现

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
前端架构师之10_JavaScript_DOM
第1级DOM(DOM Level 1,或DOM1)。为XML和HTML文档中的元素、节点、属性等提供了必备的属性和方法。结合了Netscape及微软公司开发的DHTML(动态HTML)思想。
张哥编程
2024/12/13
1790
JS之文档对象模型DOM
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gbk"> <title>History和Location使用</title> </head> <body> <input type="button" value="返回" onclick="history.back();" /> </body> </html> DOM 解析模型,将文档加载到 内存,形成一个树形结构 <html> 就是根节点,每个标签会成为
Java帮帮
2018/03/19
3.4K0
JS之文档对象模型DOM
JavaScript DOM基础
DOM(Document Object Model)即文档对象模型,针对HTML和XML文档的API(应用程序接口)。 一.DOM介绍 DOM中的三个字母,D(文档)可以理解为整个Web加载的网页文档;O(对象)可以理解为类似window对象之类的东西,可以调用属性和方法,这里我们说的是document对象;M(模型)可以理解为网页文档的树型结构。 DOM有三个等级,分别是DOM1、DOM2、DOM3,并且DOM1在1998年10月成为W3C标准。DOM1所支持的浏览器包括IE6+、Firefox、Safa
汤高
2018/01/11
1.4K0
HTML DOM(二):节点的增删改查
       上一篇:HTML DOM(一)        上一篇讲述了DOM的基本知识,从其得知,在DOM眼中,HTML的每个成分都可以看作是节点(文档节点、元素节点、文本节点、属性节点、注释节点,
高爽
2017/12/28
1.7K0
关于DOM的理解
当创建了一个网页并把它加载到web浏览器中时,DOM就悄然而生。浏览器根据网页文档创建一个文档对象。
Tz一号
2020/09/10
1K0
前端之BOM和DOM
BOM(Browser Object Model)浏览器对象模型,它使得JS能够与浏览器进行‘对话’(交互,通过JS对页面内容进行操作)。
GH
2019/12/16
2.8K0
前端之BOM和DOM
前端day13-JS(WebApi)学习笔记(attribute语法、DOM节点操作)
小技巧:如果API写的是Emement复数的形式,也就是后面加了s(Emements)那么它返回的就是一个伪数组 否则就是单个对象,一般只有id才会是单个对象,其他方式获取(标签名 类名)都是伪数组.
帅的一麻皮
2020/04/19
3.1K0
前端day13-JS(WebApi)学习笔记(attribute语法、DOM节点操作)
JavaScript 编程精解 中文第三版 十四、文档对象模型
当你在浏览器中打开网页时,浏览器会接收网页的 HTML 文本并进行解析,其解析方式与第 11 章中介绍的解析器非常相似。浏览器构建文档结构的模型,并使用该模型在屏幕上绘制页面。
ApacheCN_飞龙
2022/12/01
1.5K0
JavaScript 编程精解 中文第三版 十四、文档对象模型
从零开始学习BOM&amp;DOM
ECMAScript,描述了该语言的语法和基本对象,如类型、运算、流程控制、面向对象、异常等。
虎妞先生
2022/09/19
6140
从零开始学习BOM&amp;DOM
前端之HTML DOM操作
当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。
山河木马
2019/03/05
6090
JavaWeb——JavaScript精讲之DOM、BOM对象与案例实战(动态添加删除表格)
上一博文种讲解了JavaScript基础的ECMAScript,包括基本语法和部分对象,本文中继续讲解JavaScript中比较重要的两部分内容BOM、DOM及事件,后文中有对应的实战练习。
Winter_world
2020/09/25
2.3K0
JavaWeb——JavaScript精讲之DOM、BOM对象与案例实战(动态添加删除表格)
jQuery文档对象模型DOM的实际应用
DOM 在 JavaScript 课程中我们详细的探讨过,它是一种文档对象模型。方便开发者对 HTML 结构元素内容进行展示和修改。在 JavaScript 中,DOM 不但内容庞大繁杂,而且我们开发的过程中需要考虑更多的兼容性、扩展性。
王小婷
2018/12/19
1.2K0
DOM 文档对象模型
HTML 模板<html> <head> <title>我是网站标题</title> </head> <body> <div class="box"> <div class="box1"></div> </div> <div name="xiaoming"></div> <div id="box"></div> </body></html>访问节点通过 id 访问指定节点 getElement
菜园前端
2023/05/10
5160
javascript之DOM操作
http://www.cnblogs.com/kissdodog/archive/2012/12/25/2833213.html
bear_fish
2018/09/19
5560
js 深度解析DOM
因为document是window的一个属性,因为属性都是对象拥有的,所以他是一个object;
贵哥的编程之路
2020/11/03
5.1K0
js 深度解析DOM
E006Web学习笔记-JavaScript(四):DOM
将标记语言文档的各个部分,封装为对象,可以使用这些对象,对标记语言文档进行CRUD(增删改查)的动态操作;
訾博ZiBo
2025/01/06
890
E006Web学习笔记-JavaScript(四):DOM
3-DOM
将标记语言文档(HTML,XML…)的各个部分,封装为对象,可以使用这些对象,对标记语言文档进行CRUD动态操作
Ywrby
2022/10/27
1.4K0
第85节:Java中的JavaScript
后代选择器: 选择器1 选择器2 子元素选择器:选择器1 > 选择器2 选择器分组: 选择器1,选择器2,选择器3{} 属性选择器:选择器[属性名称='属性值']
达达前端
2019/07/03
2.7K0
第85节:Java中的JavaScript
【Java 进阶篇】深入理解 JavaScript DOM Node 对象
在前端开发中,与HTML文档进行交互是一项基本任务。文档对象模型(Document Object Model,简称DOM)为开发者提供了一种以编程方式访问和操作HTML文档的方式。DOM的核心是节点(Node)对象,它代表了文档中的各个部分。本博客将深入探讨JavaScript DOM Node对象,帮助您更好地理解它的作用和如何使用。
繁依Fanyi
2023/10/19
3700
Js DOM
要创建新的 HTML 元素 (节点)需要先创建一个元素,然后在已存在的元素中添加它。
hss
2022/02/25
3.9K0
相关推荐
前端架构师之10_JavaScript_DOM
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验