Javascript. Observer pattern

Паттерн Наблюдатель (Observer) - определяет отношение "один-ко-многим" между объектами таким образом, что при изменении состояния одного объекта происходит автоматическое оповещение и обновление всех зависимых объектов.
При использовании паттерна возможен как запрос, так и активная доставка данных от субъекта (запрос считается более "правильным"). Данный паттерн относится к поведенческим паттернам.


Рассмотрим примеры реализации данного паттерна.

1. Модель активной доставки данных

/* interface Observer */

var Observer = function () {
    this.update = function () {};
};

/* interface Observable */

var Observable = function () {
    this.registerObserver = function () {};
    this.removeObserver = function () {};
    this.notifyObservers = function () {};
};

/* ConcreteObservable - WeatherData */

var WeatherData = function () {
   
    var observers = [],
        temperature,
        humidity,
        pressure;
   
    this.registerObserver = function (o) {
        observers.push(o);
    };
   
    this.removeObserver = function (o) {
        var index = observers.indexOf(o);
        if (index >= 0) {
            observers.splice(index, 1);
        }
    };
   
    this.notifyObservers = function () {
        for (var observer in observers) {
            observers[observer].update(temperature, humidity, pressure);
        }
    };
   
    this.setMeasurements = function (_temperature, _humidity, _pressure) {
        temperature = _temperature;
        humidity = _humidity;
        pressure = _pressure;
        this.notifyObservers();
    };
   
};

WeatherData.prototype = new Observable();
WeatherData.prototype.constructor = WeatherData;

/* ConcreteObserver - CurrentConditionsDisplay */

var CurrentConditionsDisplay = function (weatherData) {
   
    var temperature,
        humidity,
        weatherData = weatherData;
   
    weatherData.registerObserver(this);
   
    this.update = function (_temperature, _humidity, _pressure) {
        temperature = _temperature;
        humidity = _humidity;
        this.display();
    };
   
    this.display = function () {
        console.log("Current values: " + temperature + " degrees Celsius and " + humidity + "% humidity");
    };
   
};

CurrentConditionsDisplay.prototype = new Observer();
CurrentConditionsDisplay.prototype.constructor = CurrentConditionsDisplay;

/* test application - WeatherStation */

var WeatherStation = function () {

    var weatherData = new WeatherData();
   
    var currentDisplay = new CurrentConditionsDisplay(weatherData);
   
    weatherData.setMeasurements(29, 65, 30.4);
    weatherData.setMeasurements(39, 70, 29.4);
    weatherData.setMeasurements(42, 72, 31.4);
   
}

WeatherStation();


На выходе:

Current values: 29 degrees Celsius and 65% humidity
Current values: 39 degrees Celsius and 70% humidity
Current values: 42 degrees Celsius and 72% humidity


2. Модель запроса данных

/* interface Observer */

var Observer = function () {
    this.update = function () {};
};

/* interface Observable */

var Observable = function () {
    this.registerObserver = function () {};
    this.removeObserver = function () {};
    this.notifyObservers = function () {};
};

/* ConcreteObservable - WeatherData */

var WeatherData = function () {
   
    var observers = [],
        changed = false,
        temperature,
        humidity,
        pressure;
   
    this.registerObserver = function (o) {
        observers.push(o);
    };
   
    this.removeObserver = function (o) {
        var index = observers.indexOf(o);
        if (index >= 0) {
            observers.splice(index, 1);
        }
    };
   
    this.notifyObservers = function () {
        if (changed) {
            for (var observer in observers) {
                observers[observer].update(this);
            }
            changed = false;
        }
    };
   
    this.setMeasurements = function (_temperature, _humidity, _pressure) {
        temperature = _temperature;
        humidity = _humidity;
        pressure = _pressure;
        this.measurementsChanged();
    };
   
    this.measurementsChanged = function () {
        this.setChanged();
        this.notifyObservers();
    };
   
    this.setChanged = function () {
        changed = true;
    };
   
    this.getTemperature = function () {
        return temperature;
    };
   
    this.getHumidity = function () {
        return humidity;
    };
   
    this.getPressure = function () {
        return pressure;
    };
   
};

WeatherData.prototype = new Observable();
WeatherData.prototype.constructor = WeatherData;

/* ConcreteObserver - CurrentConditionsDisplay */

var CurrentConditionsDisplay = function (_weatherData) {
   
    var temperature,
        humidity,
        weatherData = weatherData;

    this.update = function (obs) {
        if (obs instanceof WeatherData) {
            var weatherData = obs;
            temperature = weatherData.getTemperature();
            humidity = weatherData.getHumidity();
            this.display();
        }
    };
   
    this.display = function () {
        console.log("Current values: " + temperature + " degrees Celsius and " + humidity + "% humidity");
    };
   
    (function (widget) {
        weatherData = _weatherData;
        weatherData.registerObserver(widget);
    })(this);
   
};

CurrentConditionsDisplay.prototype = new Observer();
CurrentConditionsDisplay.prototype.constructor = CurrentConditionsDisplay;

/* test application - WeatherStation */

var WeatherStation = function () {

    var weatherData = new WeatherData();
   
    var currentDisplay = new CurrentConditionsDisplay(weatherData);
   
    weatherData.setMeasurements(29, 65, 30.4);
    weatherData.setMeasurements(39, 70, 29.4);
    weatherData.setMeasurements(42, 72, 31.4);
   
}

WeatherStation();


На выходе получаем аналогичный результат:

Current values: 29 degrees Celsius and 65% humidity
Current values: 39 degrees Celsius and 70% humidity
Current values: 42 degrees Celsius and 72% humidit
y