JavaScript设计模式(三)

观察者模式

观察者模式又叫发布-订阅模式,是我们常见的设计模式(其实二者有所区别,具体可baidu), 它定义对象间的一种一对多的依赖关系, 当一个对象的状态发生改变时, 所有依赖于它的对象都将得到通知。观察者模式提供了一个订阅模型,其中对象订阅事件并在发生时得到通知,这种模式是事件驱动的编程基石,它有利益于良好的面向对象的设计。

可能我们对该模式的理解还不够清晰,举个🌰:

小米最近看上了一套房子,但是去购买时发现房子已出售,售楼小姐告诉他过一阵子还有新的楼盘出售,然后小米就在之后每天都给售楼小姐打电话询问,我们一定会觉得这种行为很🤷‍♂️,所以实际上是这样的:在小米离开售楼部时,留下了自己的联系方式,当楼盘开始出售时,售楼小姐发短信通知她。在这个例子中,小米订阅了售楼部的消息,作为订阅者;售楼小姐发送通知,作为发布者,这就是生活中的发布订阅模式。

代码实现:

let SalesOffice = {
            arr: [], //花名册
            reception: function(fn) { //将客户的电话存入花名册 
                this.arr.push(fn);
            },
            sendMsg: function() {
                for (let i = 0, list = this.arr, fn; fn = list[i++];) {
                    fn.apply(this, arguments);
                }
            }
        }
		SalesOffice.reception(function(size, money) {
            console.log(size + '平方' + '\n' + money + '元');
        })
        SalesOffice.sendMsg(80, 5000000);

使用场景
一、DOM操作
       只要我们曾经在DOM节点上面绑定过事件函数,那我们就使用过观察者模式,应为JS和DOM之间就是实现了一种观察者模式。

document.body.addEventListener("click", function() {
    alert("Hello")
}false )
document.body.click() //用户点击

在上面的代码中,我们监听用户点击 document.body 的动作,但是我们是没办法预知用户将在什么时候点击的。因此我们订阅了 document.body 的 click 事件,当 body 节点被点击时,body 节点便会向订阅者发布 “Hello” 消息。

二、自定义事件
       很多时候,内置事件无法满足我们的需求,于是需要我们自定义事件,举个🌰:

const event = {
    clientList: {},//事件列表
    listen: function(key, fn) {//监听事件函数
        if (this.clientList[key]) {
            this.clientList[key] = []
        }
        this.clientList[key].push(fn)//将回调函数推入对象的键对应的值
    },
    trigger: function() {//触发事件函数
        const key = Array.prototype.shift.call(arguments)
        const fns = this.clientList[key]
        if (!fns || fns.length === 0 ) {
            return false//如果回调数组不存在或为空则返回false
        }
        for (let i = 0, fn ;fn = fns[i++];) {
            fn.apply(this, arguments)//循环回调数组执行回调函数
        }
    },
    remove : function(key , fn) {//移除事件函数
        const fns = this.clientList[key]
        if (!fns) {
            return false//事件不存在直接返回false
        }
        if (!fn) {
            delete list[key]; //如果没有后续参数,则删除整个回调数组
        } else {
            for (let l = fns.length - 1; l>=0; l--) {
                const _fn = fns[l]
                if ( _fn === fn) {
                    fns.splice(l, 1)//删除特定回调数组中的回调函数
                }
            }
        }
}

const installEvent = obj => {
    for (let i in event) {
        obj[i] = event[i]
    }
}

添加发布订阅功能

const events = {}
installEvent(events)

// 订阅信息
events.listen('newMessage', fn1 = say => {
    console.log('say:' + say)
})

// 发布信息
events.trigger('newMessage', "Hello")

//移除订阅
events.remove('newMessage', fn1)

总结
观察者模式有两个明显的优点
时间上解耦
对象间解耦
既可用于异步编程中,也可以用帮助我们完成更松耦合的代码编写。
它应用广泛,但是也有缺点,创建订阅者本身要消耗一定的时间和内存;观察者模式弱化了对象之间的联系,这本是好事情,但如果过度使用,对象与对象之间的联系也会被隐藏的很深,会导致项目的难以跟踪维护和理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值