Use JS to understand the design pattern (2)-Observer pattern

Posted May 25, 20204 min read

Foreword

If you use vue for development, then you are already using the observer mode, and it is also a point frequently asked by interviews-vue's responsive principle. When you read this pattern, you will find that the original responsive principle of vue is also very simple. So that's the point of view:the most important thing about the learning model is to understand the idea, not to realize it concretely.

Observer mode

Observer mode:Observer mode defines one-to-many between objects. In this way, when an object changes state, all its dependents will be notified and automatically updated.

In fact, this definition has clearly explained the core of the observer pattern, but in order to make this pattern better understood, the old example still tells the example in the book and provides the es6 code.

example

After the duck software last night, Xiao Li was assigned to a new project team, the Meteorological Observation Team. His task is to complete an application that can use the WeatherData object given by a weather observatory to display on different bulletin boards(displaying weather data). When the WeatherData object detects new data, these bulletin boards need to be real Update.

The WeatherData class of the weather station is as follows:

class WeatherData {
    getTemperature() {} //Get temperature
    getHumidity() {} //Get humidity
    getPressure() {} //Get air pressure
   /*
    * This method will be called once the weather measurement is updated
    * /
    measurementsChange() {}
}

After seeing the code, Xiao Li suddenly understood that his job was to deal with the data update of the bulletin board in MeasurementsChange. Xiao Li immediately wrote a simple code.

measurementsChange() {
    let temp = this.getTemperature();
    let humidity = this.getHumidity();
    let pressure = this.getPressure();

    //The following three different bulletin boards
    display1.update(temp, humidity, pressure);
    display2.update(temp, humidity, pressure);
    display3.update(temp, humidity, pressure);
}

After writing this simple and rough code, Xiao Li immediately realized that he violated many design principles and there were many obvious problems in the code. For example, if you add or delete a bulletin board, you need to modify the code, so you cannot dynamically add or delete a bulletin board. And there is no part that will be changed for encapsulation.

Since the code is problematic and there are examples that are so suitable for the observer pattern, then transform it into code implemented by the observer pattern.

class Observeable {
    observerList = []
    registerObserver(observer) {//Join subscriber
        this.observerList.push(observer);
    }
    removeObserver(observer) {//remove subscriber
        //Different examples have different implementations
        let idx = this.observerList.findIndex(val => val.name === observer.name);
        if(idx> -1) this.observerList.splice(idx, 1);
    }
    notifyObservers(... data) {//notify subscribers
        this.observerList.forEach(val => val.update(... data));
    }
}

class WeatherData {
    observeable = new Observeable() //inheritance can also be used
    measurementsChange() {
        let temp = this.getTemperature();
        let humidity = this.getHumidity();
        let pressure = this.getPressure();
        this.observeable.notifyObservers(temp, humidity, pressure);
    }
}

class Observer {
    update() {}
}

class Display1 extends Observer() {
    constructor(weatherData) {
        super();
        weatherData.observeable.registerObserver(this); //Register yourself in weatherData
    }
    update(temp, humidity, pressure) {
        //Perform the data processing of your own bulletin board and then display
    }
}
//Display2, Display3 and so on

//Main process code
main() {
    const weather = new WeatherData();
    let display1 = new Display1(weather);
    let display2 = new Display2(weather);
    let display3 = new Display3(weather);
}

It can be seen that the measurementsChange in the weather class no longer cares about who is subscribing to its data changes, and when a new bulletin board is added or deleted, it does not matter.

Design principle:To work hard for loose coupling between interactive objects.

The reason why the loosely coupled design allows us to build a resilient OO system that can respond to changes is because the interdependence between objects is minimized.

Xiao Li is very happy to see that he has implemented a loosely coupled code, but also implemented the code with the observer pattern.

to sum up

Observer mode can be understood by newspaper subscription. As a business that produces newspapers, there is no need to know who subscribes or unsubscribes to the newspapers every day. Businesses only need to distribute newspapers according to the subscription list when new newspapers are published. As a person who subscribes to a newspaper, only needs to care about the subscription, and the merchant will deliver it as soon as a new newspaper comes out.

At this point, look back and look at the vue responsive principle mentioned at the beginning to understand. It is mainly a clever use of Object.defineProperty to turn all object properties into getter/setter, which corresponds to registerObserver/notifyObservers in the above code. Once an object gets the getter of another object, it will register into its subscriber list. If the later object's setter method is called, it means that the data has changed. Then call the update function of the subscriber list to achieve Responsive principle.

Of course, there are more problems in actual implementation, but this is the core of the responsive principle. You can also try to implement a simple model.