Modelli di progettazione per gli ascoltatori di eventi di modifica del coordinamento

5

Ho lavorato con il pattern Observer in JavaScript usando varie librerie popolari per un certo numero di anni (YUI e jQuery). È spesso necessario osservare un insieme di modifiche del valore della proprietà (ad esempio, rispondere solo quando cambiano 2 o più valori specifici). C'è un modo elegante per "iscriversi" al gestore in modo che venga chiamato solo una volta? C'è qualcosa che mi manca o che non funziona nel mio progetto?

    
posta Kreegr 21.04.2012 - 04:34
fonte

4 risposte

1

Sì. Per questo sono tornato al libro originale "Gang of Four" su Design Patterns, quindi ho fatto qualche ricerca online.

Mediator - Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently. It is responsible for coordinating interactions for a group of objects.

State - Allow an object to alter its behavior when its internal state changes.

Ecco un esempio di mediatore JavaScript . Vai al fondo per l'utilizzo. Altri esempi possono o non possono essere più rilevanti per te. Ma esemplifica la nozione.

"Instead of using the Observer pattern to explicitly set many-to-many listeners and events, Mediator allows you to broadcast events globally across colleagues." — Paul Marcotte

Ecco un codice:

//A State Object is simple encapsulation of runtime activity potentially embedded in Mediator.
var interactionState = { //record state, perhaps array, look up function, or even boolean flag.}

// Un mediatore aggiunge e rimuove i componenti e trasmette eventi.

// Un mediatore scorre gli oggetti aggiunti e lo stato dei riferimenti per determinare se è necessario intervenire.

    for (var c in components) {
        if (typeof components[c]["on" + e] == "function")

          //Add in state comparison
          // if ( interactionState...) //is ready to fire action.
            //{ fire action }

          {
            try {
                //debug("Mediator calling " + e + " on " + c);
                var s = source || components[c];
                components[c]["on" + e].apply(s, a);
            } catch (err) {
                debug(["Mediator error.", e, a, s, err].join(' '));
            }
        }
    }

La tua implementazione del comportamento "apply" è probabilmente diversa e può essere semplificata.

Is there a elegant way to 'subscribe' the handler so that it is only called one time? 

Non lo considererei come "limitante degli eventi". Non c'è probabilmente alcun guadagno in termini di prestazioni, comunque. La prospettiva di cui sopra, è quella di introdurre un meccanismo decisionale che dice: "Abbiamo avuto 2 o più oggetti che attivano eventi, facciamo questo compito speciale".

Il mediatore racchiude il meccanismo decisionale, l'oggetto stato racchiude l'accumulo di informazioni in fase di esecuzione. Tieni presente che, a un certo punto, potrebbe essere necessario ripristinare lo stato. Questo comportamento di pulizia sarebbe ragionevole per essere inserito all'interno del Mediatore.

Può benissimo accadere che tu possa far ascoltare il tuo osservatore per gli eventi pubblicati, quindi chiama il mediatore per rivedere lo stato, il che rende la determinazione dell'interazione, se pertinente, quindi trasmette l'evento con le istruzioni per eseguire il loro comportamento speciale.

EDIT: controlla anche le viste Evented. Questo è un articolo eccezionale sull'argomento.

    
risposta data 21.06.2012 - 17:37
fonte
1

Il framework Reactive Extensions è stato progettato per risolvere questo problema per i gestori di eventi .NET. Potresti essere interessato a vedere come RX ti consente di rispondere alle sequenze di eventi, come descritto nella sezione "Sequencing Events" di questo post del blog . In sostanza, se sei interessato a rispondere solo quando l'utente digita "ABC" (in questo ordine), puoi dire:

IObservable<Key> keyPress = 
   Observable.FromEvent<KeyEventArgs>(Application.Current.RootVisual, "KeyUp")
      .Select(ev => ev.EventArgs.Key);

Func<Key, IObservable<Key>> pressedIs = 
   key => keyPress.Where(pressedKey => pressedKey == key);

Func<Key, IObservable<Key>> pressedIsNot = 
   key => keyPress.Where(pressedKey => pressedKey != key);

IObservable<Unit> abcPressed =
   from firstKeyPressEvent in pressedIs(Key.A)
   from secondKeyPressEvent in pressedIs(Key.B).Take(1).Until(pressedIsNot(Key.B))
   from thirdKeyPressEvent in pressedIs(Key.C).Take(1).Until(pressedIsNot(Key.C))
   select new Unit();

abcPressed.Subscribe(()=> Debug.WriteLine("ABC was pressed."));

RxJs è l'implementazione di javascript.

    
risposta data 21.06.2012 - 21:08
fonte
1

Una tecnica (utilizzando i sistemi basati su eventi con un mediatore):

Approfitto parecchio del modello di mediatore: un modo per controllare il flusso di eventi è istanziare diversi oggetti Mediator per modulo e passare solo un Mediatore specifico a ciascun modulo (come, o in una sandbox) - questo consentirà a ciascun modulo di comunicare solo attraverso quel mezzo specifico, solo quando lo dirai - e, con questo metodo, quando trasmetti messaggi, non trasmetti su tutto il sistema / mezzo su cui è in ascolto ApplicationDirector . Un'implementazione eccessivamente semplificata potrebbe essere simile a questa:

// ApplicationCore / Mediator
var mediator = new Mediator();

var media = {
    authentication: mediator.installTo({}),
    ui: mediator.installTo({}),
    clients: mediator.installTo({})
};

// ... pass each medium to the given module

function broadcast(event, data) {
    for (var medium in media) {
        media[medium].fire(event, data);
    }
}

broadcast('command://start', null);

media.ui.on('action://form/sumbit', function (data) {
    media.authentication.fire('action://form/sumbit', data.email);
    media.clients.fire('action://form/sumbit', data.name.first, data.name.last);
});

// UI Module
sandbox.mediator.on('command://start', function () {
    // ...
    sandbox.mediator.fire('action://form/sumbit', formData);
    // ...
});

// Authentication Module
sandbox.mediator.on('command://start', function () {
    // ...
    sandbox.mediator.on('action://form/sumbit', function () { /* authenticate */ });
    // ...
});

// Clients Module
sandbox.mediator.on('command://start', function () {
    // ...
    sandbox.mediator.on('action://form/sumbit', function () { /* add new client */ });
    // ...
});

Ora, puoi usare un Mediatore per gestire quando determinate modifiche (ad es. quantità) hanno un effetto sul resto del sistema. Hai persino più controllo su quando un determinato modulo dovrebbe notificare al sistema le modifiche. Inoltre, se stai sviluppando un'applicazione su larga scala, utilizzare un mediatore che implementa un EventHub è un buon approccio.

Ci sono molte cose strane su questo esempio , ma spero che tu lo trovi utile per ciò che dimostra.

    
risposta data 10.12.2014 - 02:40
fonte
0

Non lo so, se questa idea esiste già e se ha un nome - se è così, sarebbe bello se qualcuno ce lo dice: -)

Potresti aggiungere un oggetto che

  • osserva i tuoi due o tre valori,
  • è osservato dal tuo oggetto obiettivo e
  • invia solo un messaggio, se viene raggiunta la tua condizione.

Mi sembra un "proxy dell'osservatore condizionale".

    
risposta data 21.04.2012 - 10:39
fonte

Leggi altre domande sui tag