Componi elegantemente EventEmitter nidificati

3

Sto sviluppando uno strumento JavaScript lato server e sto provando a farlo in modo modulare.

Ho una classe Parser che è una EventEmitter - tu chiami parse e alla fine emetterà data e end eventi. Viene generalmente invocato in questo modo:

var parser = new Parser(options);

parser
  .on('data', handleData)
  .on('end', handleEnd)
  .parse();

Ora voglio estendere questo parser in un modo che impone una sorta di stato - piuttosto che emettere semplicemente data per ogni risultato di analisi, tiene traccia di come i risultati cambiano tra le analisi. Ho creato un'altra classe chiamata Stateful che accetta un'istanza Parser ed è costruita attorno ad essa (stile composizione). È un EventEmitter stesso ed emette insert , update , delete e end . Lo usi in questo modo:

var parser = new Stateful(new Parser(options));

parser
  .on(/* handle events */)
  .parse();

Ora voglio estendere ulteriormente questa funzionalità. Oltre allo stato di tracciamento, voglio monitorare l'ordine di questi risultati di analisi in base ad un algoritmo di ordinamento predefinito, poiché viene emesso ogni risultato di analisi. Questo ha un impatto sulle prestazioni del parser Stateful e ci sarebbe ragione di usare Stateful con l'ordinamento del tracciamento, quindi voglio tenerlo separato. Emetterà gli stessi eventi di Stateful , ma avranno alcuni oggetti aggiuntivi passati ai loro gestori.

Quindi qual è il modo migliore per farlo?

Potrei ulteriormente nidificare la composizione, in questo modo:

var parser = new Ordered(new Stateful(new Parser(options)));

Ma mi sembra maleodorante. Ordered si basa sul fatto che viene passato un Stateful e si interromperà se è stato appena passato un Parser .

In alternativa, potrei dire che Ordered eredita da Stateful , ma ricorda che Stateful comunica con eventi, a cui non piace comportarsi in modo polimorfico. Prendi questo esempio qui sotto. Ho usato la pseudo-sintassi della classe ES6 per la tersezza, fammi sapere se non è affatto chiaro. In realtà sto scrivendo questo in ES5.

class Stateful extends EventEmitter {
  constructor(parser) {
    this.parser = parser;

    parser
      .on('data', this.handleData.bind(this))
      .on('end', this.handleEnd.bind(this));
  }

  handleData(data) {
    if (isNew(data)) {
      this.emit('insert', data);
    } else {
      this.emit('update', data);
    }
  }

  handleEnd() {
    for (data in dataNotYetHandled()) {
      this.emit('delete', data);
    }
    this.emit('end');
  }
}

class Ordered extends Stateful {
  /* ??? */
}

I metodi handleData e handleEnd emettono eventi direttamente, quindi non posso utilizzarli direttamente nell'implementazione della superclasse. Potrei separare la logica dalle chiamate emit , ma ciò interromperà l'incapsulamento, richiedendo alla mia sottoclasse di utilizzare le chiamate al di fuori dell'interfaccia pubblica della sua superclasse.

Quale modello sarebbe il migliore qui? Ho il controllo di tutte e 3 le classi e posso apportare modifiche alle interfacce di ognuna di esse. Per favore fatemi sapere se potrei fornire ulteriori informazioni. Grazie.

    
posta Brandon Horst 17.12.2014 - 18:24
fonte

1 risposta

1

Ho deciso di ri-implementare la soluzione usando i Node Stream, piuttosto che semplici eventi, permettendomi di usare pipe() .

    
risposta data 20.12.2014 - 19:09
fonte