1

The observer model, also known as the "publish-subscribe" model, can effectively decouple the modules.

The observer mode is used in some scenes with a one-to-many relationship, an object has some changes, and other objects that depend on the object also need to do some actions.

For example, in class, the teacher posed a question, and all students who knew the question answered the question. Among them, the teacher is the main object, the teacher’s question is the state change, the student is the object dependent on the teacher, and the student’s answer to the question is the change made to the state of the teacher’s question.

To figure out this principle, let's take a look at how to implement it in code.

We can create an object to help us monitor the change of the main object, and we need to notify the dependent objects that have subscribed to the main object to change this time and respond accordingly. Taking the teacher's question and student answer as an example, we create an Observer object, and it must be able to To help students subscribe to a teacher to ask a question, they must also be able to send a message to the teacher, and since there is a subscription, there must be an unsubscription, so there must be a way to unsubscribe. Based on this idea, the Observer we designed is almost the same It looks like this:

const Observer = (function(){
    var _messages = {};
    return {
        add: ()=>{},   //订阅消息
        emit: ()=>{},  //发布消息
        remove: ()=>{} //取消消息的订阅
    }
})()

Create a private variable with the immediate execution function, _messages stores the subscribed messages and the operations that the subscriber wants to perform.

Next, let's look at the add method. Add stores the subscribed message and the subscriber's operations in _messages, so that when the message is sent, the subscriber can respond accordingly. So the add method can be implemented like this:

add: (type, fn)=>{        //type就是消息,fn就是订阅者的回调
    if(_messages[type]){
        _messages[type].push(fn)
    }else{
        _messages[type] = [fn] 
    }
}

The method is very simple, it is to see if there is a certain message in _messages, if not, create an array, put it in the callback party, or put it directly in the array. Because there may be multiple subscribers subscribing to the same message, an array is used.

Next is the emit method. Emit is used to send a message. In fact, it is to go to _messages to see if there are subscribers to a message, and if so, execute all the callbacks.

emit: (type, args)=>{
    if(_messages[type] && _messages[type] instanceof Array){
        for(let i = 0; i < _messages[type].length; i++){
                    typeof _messages[type][i] == 'function' && _messages[type][i].call(this, args)
        }
    }
}

The last is the remove method. In fact, it is to look for a certain message to find the callback of a certain subscriber, and just delete it.

remove: (type, fn)=>{
   if(_messages[type] && _messages[type] instanceof Array){
      for(let i = _messages[type].length - 1; i >= 0; i--){
           _messages[type][i] == fn && _messages[type].splice(i, 1);
       }
    }
}

Combined, a complete observer object is as follows:

const Observer = (function(){
    var _messages = {};
    return {
        add: (type, fn)=>{
            if(_messages[type]){
                _messages[type].push(fn)
            }else{
                _messages[type] = [fn] 
            }
        },
        emit: (type, args)=>{
            if(_messages[type] && _messages[type] instanceof Array){
                for(let i = 0; i < _messages[type].length; i++){
                    typeof _messages[type][i] == 'function' && _messages[type][i].call(this, args)
                }
            }
        },
        remove: (type, fn)=>{
            if(_messages[type] && _messages[type] instanceof Array){
                for(let i = _messages[type].length - 1; i >= 0; i--){
                    _messages[type][i] == fn && _messages[type].splice(i, 1);
                }
            }
        }
    }
})()

Next, let's see how it works, and take students answering questions as an example. Let's first come to a teacher, and the teacher will post a question:

var Teacher = function(){
    this.question = function(questionName){
        console.log('老师提问了: ' + questionName);
        Observer.emit(questionName, {question: questionName})
    }
}

Then there are students. Students have a method to answer questions, a method to monitor questions, only listening to the questions they know, and a sleeping method. Sleeping is actually to unsubscribe from a certain message.

var Student = function(name){
    this.name = name;
    this.answer = function(args){
        console.log(name +'回答老师的问题: ' + args.question);
    }
}
Student.prototype = {
    listen: function(questionName){
        console.log(this.name +'想要回答问题: ' + questionName);
        Observer.add(questionName, this.answer)
    },
    sleep: function(questionName){
        console.log(this.name +'睡着了');
        Observer.remove(questionName, this.answer)
    }
}

The listen and sleep can be placed on the prototype chain, but the answer method is placed on the instance, because if it is placed on the prototype chain again, the observer cannot tell which callback belongs to which subscriber.

With the above two objects, we combine the following code to see how the observer works:

var s1 = new Student('小明');
var s2 = new Student('小红');

s1.listen("谁最帅");
s2.listen("谁最帅");

var t = new Teacher();
setTimeout(() => {
    t.question('谁最帅');

    s1.sleep("谁最帅");
    setTimeout(() => {
        t.question('谁最帅')
    }, 2000);

}, 2000);

We created two students, listened to the question “Who is the most handsome?” and then created a teacher. The teacher asked “Who is the most handsome?” after two seconds. Both students should answer the question. Then student s1 fell asleep, so he stopped listening to "who is the most handsome?", the teacher asked again after 2 seconds, this time only student s2 answered the question.
The complete result is as follows.

小明想要回答问题: 谁最帅
小红想要回答问题: 谁最帅
老师提问了: 谁最帅

小明回答老师的问题: 谁最帅
小红回答老师的问题: 谁最帅
小明睡着了

老师提问了: 谁最帅
小红回答老师的问题: 谁最帅

The above result is that the observer is working, the two students listen to the question, the Observer inserts "who is the most handsome" into the _messages, and puts the answer methods of the two students into the array, and waits for the teacher to ask the Observer Just go to _messages and execute them in turn. Later s1 canceled the subscription, and the Observer deleted the object's subscription to the event from _messages, so when the second question was asked, s1 no longer answered.


这个少年有点热丶
363 声望12 粉丝

[链接]