Siete sulla strada giusta, cercherò di dare quella spinta in più si sta parlando:
E si desidera accoppiamento lasco, pub-sub è un buon modo andare.
Ma non è proprio questo "mediatore", ogni modulo dovrebbe idealmente essere autonomo e incapsulare la propria logica.
Questo viene fatto nel modo seguente: ogni modulo dipende dal servizio pubsub, sottoscrive tutti gli eventi rilevanti e agisce su di essi. Ogni modulo pubblica anche eventi che potrebbero essere rilevanti per gli altri (esempi di codice in un minuto, portami con me).
Penso che il bit che potreste mancare qui è che i moduli, che usano gli eventi, difficilmente saranno mai solo modelli semplici. Avranno un po 'di logica e possono anche tenere un modello (che aggiornano quando ricevono eventi).
Così, invece di un dataModule
si hanno maggiori probabilità di avere un dataLoaderModule
che pubblicherà il modello di dati (ad esempio {data: 3}
), una volta che termina il caricamento.
Un altro grande requisito che si imposta è la condivisione dei dati evitando le variabili globali di istanza: questo è un concetto molto importante e anche un passo nella giusta direzione.Quello che ti manca nella soluzione per questo è - Iniezione delle dipendenze o almeno un sistema di moduli che consente di definire le dipendenze.
Vedete, avere un'applicazione guidata da evento non significa necessariamente che ogni parte del codice dovrebbe comunicare utilizzando gli eventi. Un modello di configurazione dell'applicazione o un servizio di utilità è sicuramente qualcosa che vorrei iniettare (quando si utilizza DI, come in Angolare), richiedere (quando si usa AMD/CommonJS) o importare (quando si usano i moduli ES6).
(vale a dire piuttosto che comunicare con un'utilità che utilizza eventi).
Nel tuo esempio non è chiaro se configModule
è una configurazione di app statica o una manopola che posso modificare dall'interfaccia utente. Se è una configurazione app statica, la inietterei.
Ora, vediamo alcuni esempi:
Assumendo il seguente:
- Invece di un
dataModule
abbiamo un dataLoaderModule
configModule
è un modello statico configuration
.
- Stiamo usando i moduli AMD (e non i moduli ES6, che preferisco), dal momento che ti vedo bloccato usando solo le funzionalità ES5 (non vedo classi o Sali).
Avremmo:
data-loader.js (aka dataLoaderModule)
define(['pubsub'], function (pubsub) {
// ... load data using some logic...
// and publish it
pubsub.publish('data-loaded', {data: 3});
});
configuration.js (aka configModule)
define([], function() {
return {factor: 2};
});
display.js (aka 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);
});
});
questo è tutto.
Si noterà che non abbiamo qui alcuna variabile globale (nemmeno pubub), ma invece stiamo richiedendo (o iniettando) le nostre dipendenze.
Qui si potrebbe chiedere: "e cosa succede se ho voluto che la mia configurazione per cambiare dall'interfaccia utente?", quindi vediamo anche questo:
In questo caso, piuttosto rinominare configModule
in settingsDisplayModule
(seguendo la convenzione di denominazione).
Inoltre, in un'app più realistica, i moduli dell'interfaccia utente solitamente contengono un modello, quindi facciamolo anche noi.
e permette anche loro "punti di vista" invece di "displayModules" chiamare, e avremo:
data-loader.js (aka dataLoaderModule)
define(['pubsub'], function (pubsub) {
// ... load data using some logic...
// and publish it
pubsub.publish('data-loaded', {data: 3});
});
impostazioni -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);
}
};
});
data-view.js (aka 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();
});
});
E questo è tutto.
Speranza che aiuta :)
In caso contrario - commento!
sembra che il tuo init dovrebbe sparare dopo ogni cambiamento, nel qual caso dovrebbe essere chiamato render. guarda nel modello di redux, è fondamentalmente un emettitore di eventi come te, con un evento jolly che re-rende lo stato. – dandavis
_Ma così mi sembra di finire con un mediatore che deve conoscere tutte le istanze del modulo esplicitamente_ No, non lo fai. Perchè pensi questo? La funzione subscribe dovrebbe essere chiamata all'interno del contesto di un modulo. E tutto ciò che pubub deve sapere è richiamare la richiamata che viene data. – sahbeewah