Re0:从零开始的JavaScript - 观察者模式的理解

一、定义

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

在这里先讲一下面向对象设计的一个重要原则——单一职责原则。因此系统的每个对象应该将重点放在问题域中的离散抽象上。因此理想的情况下,一个对象只做一件事情。这样在开发中也就带来了诸多的好处:提供了重用性和维护性,也是进行重构的良好的基础。几乎所有的设计模式都是基于这个基本的设计原则来的。

观察者模式(又被称为发布-订阅(Publish/Subscribe)模式。说到发布订阅,最熟悉的就是我们的微信公众号了,那就用这个来举例子:


image

观察者模式的简单实现

假设微信用户就是观察者,微信公众号是被观察者,有多个的微信用户关注了程序猿这个公众号,当这个公众号更新时就会通知这些订阅的微信用户。

先实现微信公众号的类

/* 所有公众号 */
class Pubsub {
    /*
        follows 保存公众号下的用户和用户的操作,数据结构如下:
        {
            ["Github最新开源项目"]: [ {id: 0, fn: fn} , {id: 1, fn: fn} , {fn: fn} ],
            ["CNode社区新闻"]: [ {id: 0, fn: fn} , {id: 1, fn: fn} , {fn: fn} ],
        }
    * */
    constructor (){
        this.follows = {}
        this.id = -1
    }
    /* 订阅方法
     * @param {string} userName 公众号名
     * @param {function} fn 公众号发布文章后用户会采取的操作
     * @return {string} id 每个用户在公众号中的唯一标识
     * */
    subscrilb(pubsubName, fn) {
        this.follows[pubsubName] || (this.follows[pubsubName] = [])
        let id = '' + (++this.id)
        this.follows[pubsubName].push({ id, fn })
        return id
    }

    /* 发布方法
     * @param {string} userName 公众号名
     * */
    publish (pubsubName) {
        let len = this.follows[pubsubName].length;
        for (let i = 0; i < len; i++) {
            console.log(this.follows)
            this.follows[pubsubName][i].fn()
        }
    }

    /* 取消订阅方法
     * @param {string} userName 公众号名
     * @return {string} id 每个用户在公众号中的唯一标识
     * */
    unsubscribe(pubsubName, id) {
        for (let key of this.follows) {
            if(key == pubsubName) {
                for (let i = 0,len = this.follows[pubsubName].length; i< len; i++) {
                    if (this.follows[pubsubName][i].id === id) {
                        this.follows[pubsubName].splice(i, 1)
                    }
                }
            }
        }
    }
}

let pubsub = new Pubsub();

接下来设置用户类

class User {
    constructor(name){
        this.name = name
    }
    /* 
    * 用户订阅方法
    **/
    follow(pubsubName, fn) {
        pubsub.subscrilb(pubsubName, fn)
    }
}

let user1 = new User('user-1')
let user2 = new User('user-2')

然后进行订阅发布

user1.follow('CNode社区新闻',function() {
    console.log('user 1 关注此社区!')
})
user2.follow('CNode社区新闻',function() {
    console.log('user 2 关注此社区!')
})
pubsub.publish('CNode社区新闻')


user1.follow('Github最新咨询',function() {
    console.log('user 1 关注此社区!')
})
user2.follow('Github最新咨询',function() {
    console.log('user 2 关注此社区!')
})
pubsub.publish('Github最新咨询')

观察者模式优缺点

优点:

  • 我们作为订阅者不必每次都去查看这个公众号有没有新文章发布, 公众号作为发布者会在合适时间通知我们

  • 我们与公众号之间不再强耦合在一起。公众号不关心谁订阅了它,
    不管你是男是女还是宠物狗,它只需要定时向所有订阅者发布消息即可

  • 可以广泛应用于异步编程,它可以代替我们传统的回调函数
    我们不需要关注对象在异步执行阶段的内部状态,我们只关心事件完成的时间点

缺点:

  • 在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂
  • 由于JavaScript单线程异步机制,即使一个观察者卡顿了,也不会影响整体的执行效率。(多线程同步便会阻塞)

总结

观察者模式有两个明显的优点

  • 时间上解耦
  • 对象上解耦
image

关于观察者模式,在浏览器和Node都有良好的事件机制支持,不必自己实现,本文只是简单了解。

你可能感兴趣的:(Re0:从零开始的JavaScript - 观察者模式的理解)