Observer pattern of js design pattern and its application in vue

I. Introduction

  Observer mode, also known as publish-subscribe mode, defines a one-to-many relationship, allowing multiple observer objects to monitor a certain topic object at the same time, and when the state of this topic object changes, all observing objects will be notified.

  Just as users subscribe to WeChat official accounts, one official account can be subscribed by multiple users at the same time. When the official account has new content, as long as it is published, users can receive the latest content.

  The event monitoring mechanism in js is an observer pattern.

 2. Implement a simple demo

function Public(){
    //Store subscriber information
    this.subscribers = [];

    //add subscriber
    this.addSubscriber = function(subscriber){

      // Ensure that a subscriber can only subscribe once
      let isExist = this.subscribers.some(function(item){
        return item == subscriber;
      })

      if(!isExist){
        this.subscribers.push(subscriber);
      }
      
      return this;
    }

    //make an announcement
    this.deliver = function(data){
      this.subscribers.forEach(function(fn){
        fn(data)
      })

      return this;
    }
  }

------------------------------------------------------
//subscriber
let a =  function(data){
  console.log(`Subscriber a received subscription information: ${data}`)
}
let b = function(data){
  console.log(`Subscriber b received subscription information: ${data}`)
}
let c = function(data){
  console.log(`Subscriber c received subscription information: ${data}`)
}

//initialization
let publisher = new Public();

//add subscriber
publisher.addSubscriber(a);
publisher.addSubscriber(b).addSubscriber(c);

//public account release news
publisher.deliver('This is the first new information pushed by the official account!');  
publisher.deliver('This is the second new message pushed by the official account!').deliver('This is the third new message pushed by the official account!');  

2. It can be seen that the observer mode has the following advantages

1. Each subscriber is independent of each other and only has a relationship with the publisher. It has a one-to-many relationship with the publisher, or a one-to-one relationship.
2. Each subscriber can call according to their own needs without affecting other subscribers.
2. Compared with the first method, the code of the second method is more readable and maintainable;

3. Complete demo

The above is relatively simple.

function Public() {
  this.handlers = {};
}
Public.prototype = {
    // Subscribe to events
    on: function(eventType, handler){
        var self = this;
        if(!(eventType in self.handlers)) {
           self.handlers[eventType] = [];
        }
        self.handlers[eventType].push(handler);
        return this;
    },
     // trigger event (publish event)
    emit: function(eventType){
       var self = this;
       var handlerArgs = Array.prototype.slice.call(arguments,1);
       for(var i = 0; i < self.handlers[eventType].length; i++) {
         self.handlers[eventType][i].apply(self,handlerArgs);
       }
       return self;
    },
    // delete subscription event
    off: function(eventType, handler){
        var currentEvent = this.handlers[eventType];
        var len = 0;
        if (currentEvent) {
            len = currentEvent.length;
            for (var i = len - 1; i> = 0; i -) {
                if (currentEvent[i] === handler){
                    currentEvent.splice(i, 1);
                }
            }
        }
        return this;
    }
};

var Publisher = new Public();

//Subscribe to event a
Publisher.on('a', function(data){
    console.log(1 + data);
});
Publisher.on('a', function(data){
    console.log(2 + data);
});

// trigger event a
Publisher.emit('a', 'I am the parameter of the first call');

Publisher.emit('a', 'I am the parameter of the second call');  

Fourth, the role of vue

  Vue will traverse the data property of the instance, set each data as an accessor, then set it as a watcher in the getter function of the property, and publish the change message to other watchers in the setter.

  In this way, with the publish/subscribe mode, changing one of the values ​​will publish a message, and all watchers will update themselves. These watchers are the display information bound in the dom.

  So as to achieve the effect of changing the browser dom and changing in real time in the browser, the code is as follows:

   // Traverse the properties of the data object of the incoming instance and set it as the accessor property of the Vue object
    function observe(obj,vm){
        Object.keys(obj).forEach(function(key){
            defineReactive(vm,key,obj[key]);
        });
    }
    //Set as an accessor property, and in its getter and setter functions, use the subscribe-publish mode. monitor each other.
    function defineReactive(obj,key,val){
        //The observer (subscription/publish) mode is used here, which defines a one-to-many relationship, allowing multiple observers to monitor a subject object, and all observer objects will be notified when the state of the subject object changes. Observer objects can then update their own state.
        //Instantiate a subject object with an empty list of observers in the object
        var dep = new Dep();
        //Set each property of data to the accessor property of the Vue object, the property name is the same as that in data
        //So every time you modify Vue.data, the get and set methods below will be called. Then it will listen to the input event of v-model. When the value of input is changed, the data of Vue.data will be changed accordingly, and then the set method here will be triggered.
        Object.defineProperty(obj,key,{
            get: function(){
                //Dep.target pointer points to watcher, add subscriber watcher to the main object Dep
                if(Dep.target){
                    dep.addSub(Dep.target);
                }
                return val;
            },
            set: function(newVal){
                if(newVal === val){
                    return
                }
                val = newVal;
                //console.log(val);
                //Notify watchers in the subscriber list
                dep.notify();
            }
        });
    }

    //Subject object Dep constructor
    function Dep(){
        this.subs = [];
    }
    //Dep has two methods, adding subscribers and publishing messages
    Dep.prototype = {
        addSub: function(sub){
            this.subs.push(sub);
        },
        notify: function(){
            this.subs.forEach(function(sub){
                sub.update();
            });
        }
    }

  

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326147697&siteId=291194637