JS设计模式之发布/订阅(Publish/Subscribe)模式

发布订阅模式在编程中用于实现一对多的通信,它降低了模块间的耦合。通过创建一个主题对象,多个订阅者可以监听该主题,当主题状态改变时,会通知所有订阅者。在实际应用如图片加载完成后的处理中,使用此模式可以避免代码结构的紧耦合,但也可能增加系统资源的开销。本文通过示例代码和案例解析了如何在JavaScript中实现和运用发布/订阅模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

发布订阅模式定义了一种一对多的依赖关系,让多个订阅者对象同时监听某一个主题对象。这个主题对象在自身状态变化时,会通知所有订阅者对象,使它们能够自动更新自己的状态。

合理的的使用订阅者模式,可以减少程序之间的耦合,但是会增加内存和时间的开销。

应用

平时开发中,我们可能会经常遇到下面的情况:

loadImage(imgAry, function () {
  Map.init();
  Gamer.init();
})
复制代码

上面代码是一个图片加载器,在图片加载完成之后渲染地图, 执行游戏逻辑,大部分时候我们也会这么写。但有有一天,我们需要在游戏里面添加背景音乐,于是我们在Gamer.init();后面添加了一句Sount.init();。表面上看起来没什么问题,但是可能会给我带来很多预想不到的结果,因为我们改变了loadImage的结构。

为了解决这种问题,我们可以把代码结构调整为下面这样:。


loadImage.listen("ready", function () {
  Map.init();
})
loadImage.listen("ready", function () {
  Gamer.init();
})
loadImage.listen("ready", function () {
  Sount.init();
})

复制代码

这样loadImage只负责载入图片,而不需要做其他的操作了,然后在图片载入成功之后,只需要通告一下,表示图片载入成功了,至于成功之后要做什么操作,loadImage无需关心。

loadImage.trigger( "ready" );          
复制代码

代码


function  pubsub  (myObject) {

    var topics = {};
    var subUid = -1;

    //  发布   (标题   参数)
    myObject.publish = function( topic, args ) {

        //只在topic的时候继续,不存在的时候返回false
        if ( !topics[topic] ) {
            return false;
        }

        //该事件的订阅者数组
        var subscribers = topics[topic];

        //数组长度
        var len = subscribers ? subscribers.length : 0;

        //调用每个通知者的函数,并且传参数
        while (len--) {
            subscribers[len].func( topic, args );
        }
        return this;
    };

    //添加订阅
    myObject.subscribe = function( topic, func ) {

        //没有订阅者的时候,初始化这个订阅者数组
        if (!topics[topic]) {
            topics[topic] = [];
        }

        //给每个订阅者添加一个token
        var token = ( ++subUid ).toString();

        //放进队列
        topics[topic].push({
            token: token,
            func: func
        });

        //返回token
        return token;
    };

    //取消订阅
    myObject.unsubscribe = function( token ) {

        //根据token取消订阅
        for ( var m in topics ) {
            if ( topics[m] ) {
                for ( var i = 0, j = topics[m].length; i < j; i++ ) {
                    if ( topics[m][i].token === token ) {
                        topics[m].splice( i, 1 );
                        return token;
                    }
                }
            }
        }
        return this;
    };
}



复制代码

案例


//接上上面的代码
var obj = {};
pubsub(obj)             //对obj对象进行加工

//回调函数
function func1 (topic,args){
    console.log('这是',topic,'事件,参数为:',args)
}

var token1=obj.subscribe ('test1', func1)  //创建一个,并且保存token

var token2=obj.subscribe ('test2', ()=>{
    console.log('test2')
})  //创建一个,并且保存token

 //输出:
 //这是 test1 事件,参数为: 测试下
 //test2

复制代码

总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值