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


    观察者模式(Observer Pattern)又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。

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

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

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

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

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

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

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

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

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

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

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

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

    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);});}};
    }; 
    
    • 1
    • 2

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

    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"); 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

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

  • 相关阅读:
    LVS负载均衡群集
    web网页设计—— 指环王:护戒使者(13页) 电影网页设计 在线电影制作 个人设计web前端大作业
    html5新增_webStorage
    无需添加udid,ios企业证书的自助生成方法
    架构基本概念和架构本质
    如何使用 FastAPI 部署 NLP 模型?
    vue如何实现登录数据的持久化
    Dynamic-DataSource多数据源配置mybatis/mybatis-plus
    yum工具的使用
    数据库备份
  • 原文地址:https://blog.csdn.net/weixin_53312997/article/details/126182815