带你了解------发布订阅者模式的步步进化,层层递进的实现

发布订阅者模式进化论

  1. 基础版本
  2. 第一步进化—仅订阅需要信息
  3. 第二步进化—通用型发布订阅
  4. 第三步进化—解耦发布者和订阅者关系
  5. 第四步进化—命名空间(防止代码越来越复杂,形成的全局冲突)

PS:发布订阅者模式可以先订阅,也可以先发布

发布订阅者模式的基础版

只要你绑定过DOM事件,你就已经是一个接触过发布-订阅模式的开发者。接下来一起来看看进化后的模式,如何带来更大的便利。
// 最简单的发布订阅模式 事件监听

document.body.addEventListener('click', function () {
    alert(1);
})

document.body.addEventListener('click', function () {
    alert(2)
})

document.body.addEventListener('click', function () {
    alert(2)
})

简单实现

// 发布者----售楼处
var publish = {}

//时间缓存----电话号码  订阅者的回调函数
publish.eventList = []

//增加订阅者
publish.listen = function (fn) {
    publish.eventList.push(fn) //加入订阅者到缓存列表
}

//发布消息
publish.triggle = function () {
    for (var i = 0, fn; fn = this.eventList[i++];) {
        fn.apply(this, arguments);
    }
}

//订阅者-------买房人订阅消息
publish.listen(function (price, squareMeter) { //小明
    console.log('价格', price);
    console.log('squareMeter=', squareMeter);
})
publish.listen(function (price, squareMeter) { //小红
    console.log('价格', price);
    console.log('squareMeter=', squareMeter);
})
//发布
publish.triggle(10000, 88)
publish.triggle(50000, 108)

第一步进化

// 我们已经实现了简单的发布订阅者模式,但是存在个问题,即使小明并没有订阅小红108平的信息,但是也会推送给他,所以我们需要改造下,使用一个key来标识自己关注的信息

// 发布者----售楼处
var publish = {}

//时间缓存----电话号码  订阅者的回调函数
publish.eventList = []

//增加订阅者
publish.listen = function (key, fn) {
    if (!this.eventList[key]) { //如果没有订阅过此类消息,则给该类消息添加缓存列表
        this.eventList[key] = [];
    }
    publish.eventList[key].push(fn) //加入订阅者到缓存列表
}

//发布消息
publish.triggle = function () {
    var key = Array.prototype.shift.call(arguments), //取出消息类型
        fns = this.eventList[key]; //取出消息类型对应的消息处理函数
    if (!fns || fns.length === 0) {
        return false; //如果没有消息对应的处理函数则返回
    }
    for (var i = 0, fn; fn = fns[i++];) { //循环ket对应的消息列表处理函数
        fn.apply(this, arguments);
    }
}
//订阅者-------买房人订阅消息
publish.listen('squareMeter88', function (price, map) { //小明
    console.log('价格', price);
    console.log('squareMeter=', map);
})
publish.listen('squareMeter108', function (price, map) { //小红
    console.log('价格', price);
    console.log('squareMeter=', map);
})
//发布
publish.triggle("squareMeter88", 10000, '北京')
publish.triggle('squareMeter108', 50000, '北京')

第二步进化

// 通用模式,让所有售楼处都有发布订阅的功能

var event = {
    eventList: [],
    listen: function (key, fn) {
        if (!this.eventList[key]) { //如果没有订阅过此类消息,则给该类消息添加缓存列表
            this.eventList[key] = [];
        }
        this.eventList[key].push(fn) //加入订阅者到缓存列表
    },
    triggle: function () {
        var key = Array.prototype.shift.call(arguments), //取出消息类型
            fns = this.eventList[key]; //取出消息类型对应的消息处理函数
        if (!fns || fns.length === 0) {
            return false; //如果没有消息对应的处理函数则返回
        }
        for (var i = 0, fn; fn = fns[i++];) { //循环ket对应的消息列表处理函数
            fn.apply(this, arguments);
        }
    },
    remove: function (key, fn) {
        var fns = this.event[key];
        if (!fns) {
            return false;
        }
        if (!fn) { //如果为传入处理的回调函数,则表示所有都需要取消  即销毁订阅模式
            fns && (fns.length = 0);
        } else {
            for (var len = fns.length - 1; len >= 0; len--) { //反向遍历事件缓存列表
                var _fn = fns[len];
                if (_fn == fn) {
                    fns.splice(len, 1);//删除订阅者的处理回调函数
                }
            }
        }
    }
}

//定义一个给对象安装发布订阅功能的函数
var installEvent = function (obj) {
    //浅复制 实现对象复制
    for (var i in event) {
        obj[i] = event[i];
    }
}

//发布
var sales = {}
installEvent(sales);

//订阅者-------买房人订阅消息
sales.listen('squareMeter88', function (price, map) { //小明
    console.log('价格', price);
    console.log('squareMeter=', map);
})
sales.listen('squareMeter108', function (price, map) { //小红
    console.log('价格', price);
    console.log('squareMeter=', map);
})
//发布
sales.triggle("squareMeter88", 10000, '北京')
sales.triggle('squareMeter108', 50000, '北京')

第三步进化

//如果说小明不只是关注sales1的88平米房子,还需要关系sales2的300平米房子 那小明就还需要订阅sales的事件,此时引出‘中介者’ 便可以方便解决此问题 只需要订阅一次即可
//实现无需知道是哪个sales发布的消息 只需要关注订阅者即可 解耦发布者无需关系推给谁 订阅者无需知道是由谁发布

// 作为中介者,让所有售楼处都有发布订阅的功能,订阅者只需要订阅一次信息
var Event = (function(){
    var eventList = {},
    listen,
    triggle,
    remove;
    listen=function (key, fn) {
        if (!eventList[key]) { //如果没有订阅过此类消息,则给该类消息添加缓存列表
            eventList[key] = [];
        }
        eventList[key].push(fn) //加入订阅者到缓存列表
    },
    triggle= function () {
        var key = Array.prototype.shift.call(arguments), //取出消息类型
            fns = this.eventList[key]; //取出消息类型对应的消息处理函数
        if (!fns || fns.length === 0) {
            return false; //如果没有消息对应的处理函数则返回
        }
        for (var i = 0, fn; fn = fns[i++];) { //循环ket对应的消息列表处理函数
            fn.apply(this, arguments);
        }
    },
    remove=function (key, fn) {
        var fns = eventList[key];
        if (!fns) {
            return false;
        }
        if (!fn) { //如果为传入处理的回调函数,则表示所有都需要取消  即销毁订阅模式
            fns && (fns.length = 0);
        } else {
            for (var len = fns.length - 1; len >= 0; len--) { //反向遍历事件缓存列表
                var _fn = fns[len];
                if (_fn == fn) {
                    fns.splice(len, 1);//删除订阅者的处理回调函数
                }
            }
        }
    }
    return {
        listen,
        triggle,
        remove
    }
})()

//订阅者-------买房人订阅消息
Event.listen('squareMeter88', function (price) { //小明
    console.log('价格', price);
})
//发布
Event.triggle('squareMeter108', 50000)

第四步进化

    这种进化,属于高级,放你了解以上三种进化后,我会努力的推送给你们,静待更新喽~~~~~~~


	关注更新,提升技术~~~~~~~~

欢迎star本人github:https://github.com/flyku

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值