乐趣区

js-观察者

观察者模式模式简介

观察者模式(又被称为发布 - 订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。

观察者模式机动

建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应做出反应。在此,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展,这就是观察者模式的模式动机。

生活中的观察者模式

现在年轻人都喜欢玩手机,比如我自己我是比较爱看直播,每个直播间都有一个订阅的按钮,如果你喜欢这个直播你就会订阅一下它,但是每个主播开播的时间是不固定的,我们不能一直盯着直播间看吧,这样很浪费时间也错过了其他的内容,所以你订阅它之后,每个主播开播都会向自己订阅的号发布自己开播的消息

代码分析

  1. 我们使用 Es6 先创建一个 class
// 发布订阅实现
    class Observer {constructor () {}}
  1. 订阅(subscribe)的函数 callback 参数用作传入的订阅者回调函数,this.subscribers.length 插入当前自己应当的位置
    subscribe (callback) {
        // 将传入的函数赋予这个数组
        this.subscribers[this.subscribers.length] = callback
    }
  1. 退订(retreatSubscribe)函数,传入退订者的回调函数,循环存储订阅者的数组 this.subscribers,根据传入的退订者和订阅者数组中对比,相同者删除订阅者
    retreatSubscribe (callback) {for(var i = 0;i < this.subscribers.length;i++) {if(this.subscribers[i] === callback){delete (this.subscribers[i])
            }
        }
    }
  1. 观察(publish)函数,观察订阅者的动作,this 指向的是这个 class Observer,将 Observer 内的函数方法赋予订阅者对象,声明数组用作存储订阅者回调函数
    make (o) {
        // this === Observer 这个对象的函数
        for(var i in this){// this[i]Observer 对象里面的每个方法
            o[i] = this[i]
            // 声明数组用作存储订阅者回调函数
            o.subscribers = []}
    }
  1. 发布(publish)函数,循环存储订阅者回调函数的数组,检测是否为函数,如果是函数进行发布消息
    // 发布
    publish (what) {for(var i = 0;i< this.subscribers.length;i++){if(typeof this.subscribers[i] === 'function'){
                // add 函数
                this.subscribers[i](what)
            }
        }
    }

代码组合起来

下面的 class 代码是我将上面步骤的组合到一起的一系列代码,由订阅对象,观察对象,发布消息,退订组成的观察者模式,也叫发布订阅

    class Observer {constructor () {}
        // 订阅
        subscribe (callback) {
            // 将传入的函数赋予这个数组
            this.subscribers[this.subscribers.length] = callback
        }
        // 退订
        retreatSubscribe (callback) {for(var i = 0;i < this.subscribers.length;i++) {if(this.subscribers[i] === callback){delete (this.subscribers[i])
                }
            }
        }
        // 观察对象
        make (o) {
            // this === Observer 这个对象的函数
            for(var i in this){// this[i]Observer 对象里面的每个方法
                o[i] = this[i]
                // 声明数组用作存储订阅者回调函数
                o.subscribers = []}
        }
        // 发布
        publish (what) {for(var i = 0;i< this.subscribers.length;i++){if(typeof this.subscribers[i] === 'function'){
                    // add 函数
                    this.subscribers[i](what)
                }
            }
        }
    }

使用上面的观察者

1. 我们必须创建一个订阅者对象

let people = {}

2. 我们观察这个对象并且赋值给这个对象可以使用的功能,我们让他可以行动,可以做出行为举止

 Observer.make(people)

3. 声明想发布的信息代码

 let wanglei = {add (what) {console.log('wanglei 给' + what);
        }
    }

4. 我们订阅一下想要发送的函数,我们这里正好是声明的函数,用来订阅用的,可以回顾上面订阅的函数代码

 Observer.subscribe(wanglei.add)

5. 发布消息我们将 qaaa 字符传递到 add 订阅函数的 what 形参里面用来组合发送消息

 Observer.publish('qaaa')
 
 // 打印
  wanglei 给 qaaa

6. 退订既然可以订阅,我们就可以退订,退订主要走的 retreatSubscribe 函数,我们将订阅者的信息传递到退订函数就可以删除这个订阅者,之后再发布就无法再接收到相关信息

 Observer.retreatSubscribe(wang.add)

观察者优缺点

那么使用完观察者之后你们有什么感触,总的来说观察者有优点也有缺点,每个事物都一样总会有优缺点,但是观察者的优点在我们部分功能中起到很多作用,我们看看它的优缺点
优点:

  1. 支持简单的广播通信,自动通知所有已经订阅过的对象
  
2. 目标对象与观察者存在的是动态关联,增加了灵活性

3. 目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用

缺点:

1. 如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间

2. 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃

3. 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化

最后我们的观察者就到这里了

退出移动版