返回

JavaScript 设计模式之发布订阅者模式

发布时间:2022-10-26 06:27:55 409
# 前端# 数据

JavaScript 设计模式之发布订阅者模式_设计模式

前面在文章介绍《​​JavaScript 设计模式之策略模式​​》为什么需要设计模式及其一种常见的设计模式。本文继续介绍另一种常见的设计模式发布订阅者模式。

先来看一个需求,天气预报系统:当极端天气发生时,气象站会发布天气警报。建筑工地、船舶和游客将根据天气数据调整其日程安排。

一旦气象站发出天气警报,会做以下事情:

  • 建筑工地:停工
  • 船舶:系泊
  • 游客:取消行程

如果要编写可用于通知天气警告的代码,改如何来组织?先来看一下代码:

function weatherWarning() {
buildingsite.stopwork();
ships.mooring();
tourists.canceltrip();
}

这是一种直观的写法,但是这种写法有很多不足的地方:

  • 耦合度太高:建筑工地、船舶和游客本来应该是分开的,但现在它们被置于相同的函数中,其中一个对象中的错误可能会导致其他对象无法工作。
  • 违反开闭原则:如果有新的订阅者加入,那么只能修改​​weatherWarning​​ 函数。

造成这种现象的原因是气象站承担了主动告知各单位的责任。这就要求气象站必须知道每一个需要了解天气状况的单位。

JavaScript 设计模式之发布订阅者模式_发布订阅_02

仔细想想,其实从逻辑上讲,建筑工地、船舶、游客都应该依靠天气预报,应该是主动积极的一方。按照这个逻辑上面的图最好的方式如下:

JavaScript 设计模式之发布订阅者模式_解耦_03

气象站发布通知,然后触发事件,建筑工地、船舶和游客订阅该事件。气象站不需要关心哪些对象关注天气预警,只需要直接触发事件即可。然后需要了解天气状况的单位主动订阅该事件。

这样,气象站与订阅者解耦,订阅者之间也解耦。如果有新的订阅者,那么它只需要直接订阅事件,而不需要修改现有的代码。

为了完成这个发布-订阅系统,需要实现一个事件订阅和分发系统,定义一个时间函数,如下:

const EventEmit = function () {
this.events = {};
this.on = function (evtName, callback) {
const eventHandler = this.events[evtName];
if (eventHandler) {
this.events[evtName].push(callback);
} else {
this.events[evtName] = [callback];
}
};
this.trigger = function (evtName, ...args) {
if (this.events[evtName]) {
this.events[evtName].forEach((eventListener) => {
eventListener(...args);
});
}
};
};

这样前面的代码可以这样重构:

const weatherEvent = new EventEmit();

weatherEvent.on("warning", function () {
// buildingsite.stopwork()
console.log("buildingsite.stopwork()");
});

weatherEvent.on("warning", function () {
// ships.mooring()
console.log("ships.mooring()");
});

weatherEvent.on("warning", function () {
// tourists.canceltrip()
console.log("tourists.canceltrip()");
});

weatherEvent.trigger("warning");

如果项目中存在多对一的依赖,并且每个模块都相对独立,那么可以考虑使用发布订阅模式来重构代码。而发布订阅模式是前端开发中最常用的设计模式,很多框架都有用到这一设计模式。

特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(0)
按点赞数排序
用户头像
精选文章
thumb 中国研究员首次曝光美国国安局顶级后门—“方程式组织”
thumb 俄乌线上战争,网络攻击弥漫着数字硝烟
thumb 从网络安全角度了解俄罗斯入侵乌克兰的相关事件时间线
下一篇
JavaScript 设计模式之策略模式 2022-10-26 05:52:11