Паттерн Наблюдатель (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% humidity