3

I am developing a server-side JavaScript tool, and trying to do so in a modular way.

I have a Parser class that is an EventEmitter - you call parse and it will eventually emit data and end events. It is generally invoked like so:

var parser = new Parser(options);

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

Now I want to extend this Parser in a way that imposes some sort of state - rather than simply emitting data for every parse result, it tracks how the results change between parses. I have built another class called Stateful that accepts a Parser instance and is built around it (composition-style). It is an EventEmitter itself and emits insert, update, delete, and end. You use it like so:

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

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

Now I want to extend this functionality further. In addition to tracking state, I want to track the order of these parse results according to some pre-defined sorting algorithm, as each parse result is emitted. This does have a performance hit over the Stateful parser, and there would be reason to use Stateful with tracking sort order, so I want to keep it separate. It will emit the same events as Stateful, but they will have some additional objects passed to their handlers.

So what is the best way to do this?

I could further nest composition, like so:

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

But that seems smelly to me. Ordered relies upon being passed a Stateful and would break if it was just passed a Parser.

Alternatively, I could say that Ordered inherits from Stateful, but remember that Stateful communicates with events, which do not like to behave polymorphically. Take this example below. I used ES6 class pseudo-syntax for terseness, let me know if it is unclear at all. I am actually writing this 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 {
  /* ??? */
}

The handleData and handleEnd methods emit events directly, so I cannot make use of them directly in the superclass implementation. I could separate the logic from the emit calls, but that would break encapsulation, requiring my subclass to make use of calls outside of its superclass's public interface.

What pattern would be best here? I am in control of all 3 classes and could make changes to the interfaces of any of them. Please let me know if I could provide any more info. Thanks.

1

I have decided to re-implement the solution using Node Streams, rather than simple events, allowing me to use pipe().

  • Would love to see a example :) .. what about something like RXjs? – amcdnl Feb 22 '16 at 13:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.