Шаблоны проектирования JavaScript: наблюдатель

Во многих случаях при изменении одной части приложения вам необходимо обновить и другие части. В AngularJS, если объект $scope обновляется, для уведомления другого компонента можно инициировать событие. Шаблон наблюдателя делает именно это — если объект изменен, он сообщает зависимым объектам, что произошло изменение.

Другой яркий пример — архитектура “модель-представление-контроллер” (MVC), где представление обновляется при изменении модели. Одним из преимуществ такого метода является разделение представления и модели для ослабления связанности кода.

Как показано на вышеприведенной диаграмме, необходимыми являются объекты subject, observer и concrete. subject содержит ссылки на конкретных наблюдателей для уведомления о любых изменениях. Объект Observer — это абстрактный класс, который позволяет конкретным наблюдателям реализовать метод notify.

Давайте рассмотрим пример кода AngularJS, который включает в себя шаблон наблюдателя через управление событиями.

// Controller 1
$scope.$on('nameChanged', function(event, args) {
    $scope.name = args.name;
});

...

// Controller 2
$scope.userNameChanged = function(name) {
    $scope.$emit('nameChanged', {name: name});
};

Работая с шаблоном наблюдателя, важно уметь различать независимый объект или субъект.

Важно отметить, что хотя шаблон наблюдателя предлагает много преимуществ, одним из его существенных недостатков является значительное падение производительности по мере увеличения числа наблюдателей. Одними из самых известных наблюдателей являются watchers. В AngularJS мы можем наблюдать за переменными, функциями и объектами. Цикл $$digest запускается всякий раз, когда объект области изменяется, и уведомляет каждого из наблюдателей о появлении новых значений.

JavaScript позволяет вам создавать свои собственные субъекты и наблюдатели. Давайте посмотрим, как это делается:

var Subject = function() {
    this.observers = [];

    return {
    subscribeObserver: function(observer) {
        this.observers.push(observer);
    },
    unsubscribeObserver: function(observer) {
        var index = this.observers.indexOf(observer);
        if(index > -1) {
        this.observers.splice(index, 1);
        }
    },
    notifyObserver: function(observer) {
        var index = this.observers.indexOf(observer);
        if(index > -1) {
        this.observers[index].notify(index);
        }
    },
    notifyAllObservers: function() {
        for(var i = 0; i < this.observers.length; i++){
        this.observers[i].notify(i);
        };
    }
    };
};

var Observer = function() {
    return {
    notify: function(index) {
        console.log("Observer " + index + " is notified!");
    }
    }
}

var subject = new Subject();

var observer1 = new Observer();
var observer2 = new Observer();
var observer3 = new Observer();
var observer4 = new Observer();

subject.subscribeObserver(observer1);
subject.subscribeObserver(observer2);
subject.subscribeObserver(observer3);
subject.subscribeObserver(observer4);

subject.notifyObserver(observer2); // Observer 2 is notified!

subject.notifyAllObservers();
// Observer 1 is notified!
// Observer 2 is notified!
// Observer 3 is notified!
// Observer 4 is notified!

Шаблон публикации-подписки

Шаблон публикации-подписки использует канал тем/событий, который находится между объектами, желающими получать уведомления (подписчики), и объектом, запускающим событие (издателем). Эта система позволяет коду определять специфичные для приложения события, которые могут передавать пользовательские аргументы, содержащие необходимые подписчику значения. Идея такого подхода состоит в том, чтобы избежать зависимостей между подписчиком и издателем.

Этот шаблон отличается от стандартного шаблона Observer, поскольку для регистрации и получения уведомлений, передаваемых издателем, любой подписчик реализует обработчик событий.

Многие разработчики предпочитают объединять шаблон проектирования публикации/подписки с наблюдателем, хотя между ними есть важное различие. Подписчики в шаблоне публикации/подписки уведомляются через некоторый носитель обмена сообщениями, а наблюдатели уведомляются путем реализации обработчика, подобного субъекту.

В AngularJS объект подписывается на событие, используя $on(‘event’, callback), а издатель публикует событие, используя $emit(‘event’, args) или $broadcast(‘event’, args).

Читайте также: 

Tags: ,

Добавить комментарий