Вся справа в слабкому з’єднанні та одній відповідальності, яка йде рука об руку з моделями MV * (MVC / MVP / MVVM) у JavaScript, які є дуже сучасними за останні кілька років.
Вільне з'єднання - це об'єктно-орієнтований принцип, в якому кожен компонент системи знає свою відповідальність і не піклується про інші компоненти (або, принаймні, намагається не піклуватися про них якомога більше). Вільна муфта - це гарна річ, тому що ви можете легко використовувати різні модулі. Ви не поєднані з інтерфейсами інших модулів. Використовуючи опублікувати / підписатися, ви поєднані лише з інтерфейсом опублікувати / підписатися, що не є великою справою - лише два способи. Отже, якщо ви вирішили повторно використовувати модуль в іншому проекті, ви можете просто скопіювати і вставити його, і він, ймовірно, спрацює або, принаймні, вам не потрібно буде багато зусиль, щоб він працював.
Говорячи про вільну зв'язок, ми повинні згадати про відокремлення проблем. Якщо ви будуєте додаток, використовуючи архітектурний зразок MV *, у вас завжди є Моделі (и) та Вид (и). Модель є діловою частиною програми. Ви можете використовувати його повторно в різних додатках, тому не годиться поєднувати його з представленням однієї програми, де ви хочете її показати, оскільки зазвичай в різних додатках ви різні види. Тож корисно використовувати публікацію / підписку для зв’язку Model-View. Коли ваша Модель змінюється, вона публікує подію, View переглядає її та оновлює себе. У вас немає жодних накладних витрат від публікації / підписки, це допоможе вам для роз'єднання. Таким же чином ви можете зберігати логіку програми, наприклад, у контролері (MVVM, MVP, це не зовсім контролер) і зберігати Погляд максимально просто. Коли ваш Перегляд змінюється (або користувач, наприклад, натискає щось на нього), він просто публікує нову подію, Контролер вловлює його і вирішує, що робити. Якщо ви знайомі зШаблон MVC або з MVVM в технологіях Microsoft (WPF / Silverlight) ви можете думати про публікацію / підписку, як шаблон спостерігача . Цей підхід використовується в таких структурах, як Backbone.js, Knockout.js (MVVM).
Ось приклад:
//Model
function Book(name, isbn) {
this.name = name;
this.isbn = isbn;
}
function BookCollection(books) {
this.books = books;
}
BookCollection.prototype.addBook = function (book) {
this.books.push(book);
$.publish('book-added', book);
return book;
}
BookCollection.prototype.removeBook = function (book) {
var removed;
if (typeof book === 'number') {
removed = this.books.splice(book, 1);
}
for (var i = 0; i < this.books.length; i += 1) {
if (this.books[i] === book) {
removed = this.books.splice(i, 1);
}
}
$.publish('book-removed', removed);
return removed;
}
//View
var BookListView = (function () {
function removeBook(book) {
$('#' + book.isbn).remove();
}
function addBook(book) {
$('#bookList').append('<div id="' + book.isbn + '">' + book.name + '</div>');
}
return {
init: function () {
$.subscribe('book-removed', removeBook);
$.subscribe('book-aded', addBook);
}
}
}());
Ще один приклад. Якщо вам не подобається підхід MV *, ви можете скористатися чимось дещо іншим (є перетин між тим, що я опишу наступним, та останнім згаданим). Просто структуруйте свою програму в різних модулях. Наприклад, подивіться у Twitter.
Якщо ви подивитеся на інтерфейс, у вас просто різні поля. Ви можете розглядати кожну скриньку як інший модуль. Наприклад, ви можете опублікувати твіт. Ця дія вимагає оновлення декількох модулів. По-перше, він повинен оновити дані свого профілю (верхнє ліве поле), але також має оновити шкалу часу. Звичайно, ви можете зберігати посилання на обидва модулі та оновлювати їх окремо, використовуючи їх загальнодоступний інтерфейс, але простіше публікувати подію просто (і краще). Це полегшить модифікацію вашої програми через слабкіше з'єднання. Якщо ви розробляєте новий модуль, який залежить від нових твітів, ви можете просто підписатися на подію "опублікувати-твіт" та обробити його. Такий підхід є дуже корисним і може зробити вашу заявку дуже відокремленою. Ви можете повторно використовувати свої модулі.
Ось основний приклад останнього підходу (це не оригінальний код щебета, це лише зразок).
var Twitter.Timeline = (function () {
var tweets = [];
function publishTweet(tweet) {
tweets.push(tweet);
//publishing the tweet
};
return {
init: function () {
$.subscribe('tweet-posted', function (data) {
publishTweet(data);
});
}
};
}());
var Twitter.TweetPoster = (function () {
return {
init: function () {
$('#postTweet').bind('click', function () {
var tweet = $('#tweetInput').val();
$.publish('tweet-posted', tweet);
});
}
};
}());
Про такий підхід чудова розмова Миколи Закаса . Для підходу MV * найкращі статті, які мені відомі, опубліковані Адді Османі .
Недоліки: Ви повинні бути обережними щодо надмірного використання публікації / підписки. Якщо у вас сотні подій, керувати ними всім може стати дуже заплутано. У вас можуть виникнути зіткнення, якщо ви не використовуєте простір імен (або не використовуєте його правильно). Розширену реалізацію Mediator, яка схожа на публікацію / підписку, можна знайти тут https://github.com/ajacksified/Mediator.js . У ньому є простір імен та такі функції, як "барботаж" подій, які, звичайно, можуть бути перервані. Ще одним недоліком публікації / підписки є тестування жорстких модулів, можливо, важко виділити різні функції в модулях і перевірити їх самостійно.