Вы находитесь на правильном пути, я постараюсь дать вам, что дополнительный толчок вы говорите:
Это вы хотите потерять сцепление, паб-саб хороший способ идти.
Но вам действительно не нужен этот «посредник», каждый модуль в идеале должен быть автономным и инкапсулировать свою собственную логику.
Это делается следующим образом: каждый модуль зависит от службы pubsub, подписывается на все соответствующие события и действует на них. Каждый модуль также публикует события, которые могут иметь отношение к другим (образцы кода в минуту, нести меня).
Я думаю, что бит, который вам может не хватать, состоит в том, что модули, в которых используются события, вряд ли будут просто простыми. У них будет некоторая логика в них и может также провести модель (которую они обновляют при получении событий).
Таким образом, вместо dataModule
у вас, скорее всего, будет dataLoaderModule
, который опубликует модель данных (например, {data: 3}
), как только он закончит загрузку.
Другим важным требованием, которое вы задаете, является совместное использование данных, избегая глобальных переменных экземпляра - это очень важная концепция, а также шаг в правильном направлении.Что вы пропустили в своем решении для этого - Инъекция зависимостей или, по крайней мере, модульная система, которая позволяет определять зависимости.
Вы видите, что приложение, управляемое событиями, не обязательно означает, что каждый фрагмент кода должен связываться с использованием событий. Модель конфигурации приложения или служебная служба - это то, что я бы вводил (при использовании DI, как в Angular), требуется (при использовании AMD/CommonJS) или импорт (при использовании модулей ES6).
(т. Е. Вместо этого обмениваться данными с утилитой, использующей события).
В вашем примере неясно, является ли configModule
статической конфигурацией приложения или некоторой ручкой, которую я могу настроить из пользовательского интерфейса. Если это статическая конфигурация приложения, я бы ее ввел.
Теперь давайте рассмотрим несколько примеров:
Предполагая следующее:
- Вместо того, чтобы
dataModule
мы имеем dataLoaderModule
configModule
статическая configuration
модель.
- Мы используем модули AMD (а не модули ES6, которые я предпочитаю), поскольку я вижу, что вы придерживаетесь только функций ES5 (я не вижу классов или констант).
Мы имеем:
данных-loader.js (ака dataLoaderModule)
define(['pubsub'], function (pubsub) {
// ... load data using some logic...
// and publish it
pubsub.publish('data-loaded', {data: 3});
});
configuration.js (ака configModule)
define([], function() {
return {factor: 2};
});
display.js (ака displayModule)
define(['configuration', 'pubsub'], function (configuration, pubsub) {
var displayModule = {
display: function (data, factor) {
console.log(data * factor);
}
};
pubsub.subscribe('data-loaded', function (data) {
displayModule.display(data, configuration.factor);
});
});
Вот это.
Вы заметите, что здесь нет глобальных переменных (даже не pubsub), вместо этого мы требуем (или вводим) наши зависимости.
Здесь Вы можете спросить: «и что, если я имел в виду для меня конфиг изменить из пользовательского интерфейса?», так что давайте посмотрим, что тоже:
В этом случае я скорее переименую configModule
в settingsDisplayModule
(следуя вашему соглашению об именах).
Кроме того, в более реалистичном приложении модули пользовательского интерфейса обычно содержат модель, поэтому давайте это сделаем.
И позволяет также называть их "мнения" вместо "displayModules", и мы будем иметь:
данных-loader.js (ака dataLoaderModule)
define(['pubsub'], function (pubsub) {
// ... load data using some logic...
// and publish it
pubsub.publish('data-loaded', {data: 3});
});
настройки -view.js (aka settingsDisplayModule, aka config)
define(['pubsub'], function (pubsub) {
var settingsModel = {factor: 2};
var settingsView = {
display: function() {
console.log(settingsModel);
// and when settings (aka config) changes due to user interaction,
// we publish the new settings ...
pubsub.publish('setting-changed', settingsModel);
}
};
});
данных-view.js (ака displayModule)
define(['pubsub'], function (pubsub) {
var model = {
data: null,
factor: 0
};
var view = {
display: function() {
if (model.data && model.factor) {
console.log(model.data * model.factor);
} else {
// whatever you do/show when you don't have data
}
}
};
pubsub.subscribe('data-loaded', function (data) {
model.data = data;
view.display();
});
pubsub.subscribe('setting-changed', function (settings) {
model.factor = settings.factor;
view.display();
});
});
И это все.
Надеется, что это помогает :)
Если нет - комментарий!
Кажется, что ваш init должен срабатывать после любых изменений, и в этом случае его следует называть рендерингом. загляните в шаблон redux, это, в основном, эмитент событий, как и у вас, с подстановочным событием, которое повторно отображает состояние. – dandavis
_However таким образом я, кажется, в конечном итоге с посредником, который должен знать все экземпляры модулей явно. Нет, вы этого не делаете. Почему вы так думаете? Функция подписки должна вызываться из контекста модуля. И все, что нужно знать pubsub, - это вызвать обратный вызов, который он задает. – sahbeewah