На прошлой неделе я поиграл с несколькими шаблонами проектирования в JavaScript (
шаблон Constructor и
Module ). Мне очень понравился шаблон Module, т.е. подход, принятый в JavaScript для включения инкапсуляции данных в класс (функции в JavaScript). Я строил приложение, используя эти шаблоны проектирования, но обнаружил, что выполнение Ajax-запроса внутри функции в модуле было неправильным подходом. JavaScript отправит запрос и начнет выполнение следующего оператора. Я хотел использовать подход, который бы выталкивал данные из Модели всякий раз, когда появлялись новые данные. Это заставило меня попробовать
«шаблон наблюдателя» в JavaScript.
Прочитав немного о
шаблоне Observer , я понял, что он используется почти во всех клиентских JavaScript-программах в виде обработчиков событий. Все события браузера являются примерами этого шаблона, т. Е. Всякий раз, когда происходит событие, запускается зарегистрированный обработчик события. Здесь вы хотите, чтобы определенная функция выполнялась всякий раз, когда происходит изменение состояния другого объекта. Функцию можно рассматривать как
Наблюдатель, который выполняет необходимое действие при изменении состояния другого объекта — назовем его «
Субъект ». «
Субъект » отвечает за уведомление
наблюдателей об изменении состояния и передачу необходимых данных своим
наблюдателям . Для этого
Субъект должен вести список наблюдателей, которые заинтересованы в получении уведомлений.
В моем приложении я пытался получить твиты, отправив запрос Ajax на сервер Twitter. Как только твиты станут доступны, я хотел, чтобы все мои наблюдатели были уведомлены о последних твитах. Здесь моя тема — «
Твиттер », который отвечает за выборку твитов и уведомление всех своих наблюдателей о появлении данных. Кроме того, он отвечает за ведение списка наблюдателей, которые заинтересованы в получении уведомлений. Я смоделировал это приложение так, чтобы определить универсальный класс
Subject и класс
Twitter , который расширил бы
класс Subject .
/*
* Define a generic class Subject with two methods
* 'addObserver' and 'notifyObserver'
*/
function Subject() {
this.observerList = [];
}
Subject.prototype.addObserver = function(observerObj) {
this.observerList.push(observerObj)
}
Subject.prototype.notifyObserver = function(msg) {
for (var i = 0, length = this.observerList.length; i < length; i++) {
this.observerList[i]['updateFn'](msg);
}
}
Здесь
класс Subject определяет массив « наблюдающий список»
и два метода «
addObserver » и «
notifyObserver ». Метод addObserver добавляет объект-наблюдатель в массив, а
notifyObserver выполняет итерацию по списку наблюдателей и отправляет уведомления всякий раз, когда появляется новое сообщение. Теперь класс Twitter может расширять класс Subject:
/*
* Define a Twitter class which extends the Subject class
*/
function Twitter(handlerName,observerObj) {
//Call the parent class - Subject
Subject.call(this);
//Handler name is the username for which tweets has to be retrieved
this.handlerName = handlerName;
//add the observer object
this.addObserver(observerObj);
//fetch the status messages
this.init();
}
Twitter.prototype = Object.create(Subject.prototype);
//Define the init method that will fetch the status messages
Twitter.prototype.init = function() {
parent = this;
$.ajax({
url: 'http://twitter.com/statuses/user_timeline/' + parent.handlerName + '.json?callback=?',
success: function(data) {
//iterate over the list of tweets
$.each(data,function(index,value)
{
var message = value.text;
//ignore the reply messages i.e. messages that start with '@'
if(message[0] != '@')
{
//Check whether the status message contains a link
if((index=message.indexOf('http://')) > 0)
{
substr1 = message.substr(index);
nextIndex = substr1.indexOf(' ');
substr2 = (nextIndex > 0)? substr1.substr(0,substr1.indexOf(' ')):substr1.substr(0);
pos1 = message.indexOf(substr2);
pos2 = pos1 + substr2.length;
newMessage = [message.slice(0,pos1),'<a href='+ substr2+ ' target="_blank" >' + substr2 + '</a>',message.slice(pos2)].join('');
//notify the Observer of the new message
parent.notifyObserver(newMessage);
}
else {
parent.notifyObserver(message);
}
}
});
},
//if there is an error, throw an Error message
error: function(data) {
parent.notifyObserver("Error");
},
dataType: 'json'
});
}
Конструктор
класса Twitter вызовет родительский конструктор, а затем добавит
объект наблюдателя (путем вызова addObserver) в список. Теперь он готов получить твиты для предоставленного handlerName. Затем
функция init отправляет Ajax-запрос для получения твитов, и после получения данных она вызывает
функцию notifyObserver . Обратите внимание, что
функция notifyObserver определена в
классе Subject . Реализация
Observer довольно проста:
//Define an Observer class
function Observer(name, updateFn) {
this.name = name;
this.updateFn = updateFn;
}
//Create an instance of Observer class
observerObj = new Observer("observer1", function(msg) { console.log(msg); });
//Create an instance of the Subject and provide the observer object
tObject = new Twitter("sagarganatra",observerObj);
Наблюдатель должен предоставить функцию (или обработчик) , который должен быть вызван , когда Subject имеет новое сообщение. В этом случае updateFn будет регистрировать сообщения, которые он получает от субъекта.