Comparison between different Observer Pattern implementations

Moshe Bildner edited this page Sep 9, 2015 · 18 revisions

The comparison below is just about the basic features of subscribing to an event type, dispatching and removing an event listener. It isn't based on available features but on differences between basic implementations of each concept and pros and cons of using each one. Some things listed as cons can be avoided by "smart implementations" and "hacks" but are usually present on most cases.

All the implementations accomplish the same task and are based on the same design pattern (Observer), they also have many things in common but do things in a slightly different way. This page is intended to help you choose which one fits better your work flow and the kind of problems you are trying to solve.

Event Emitter/Target/Dispatcher

  • Each Object that dispatches custom events needs to inherit from an EventEmitter/EventTarget/EventDispatcher object or implement the proper interface.
  • Use strings to identify the event type.
  • DOM2/DOM3 Events are based on this paradigm.

Code sample

  myObject.addEventListener('myCustomEventTypeString', handler);
  myObject.dispatchEvent(new Event('myCustomEventTypeString'));
  myObject.removeEventListener('myCustomEventTypeString', handler);

Pros

  • Total control of the target object and make sure you are listening only to the events dispatched by the specific target.
  • Can dispatch arbitrary event types without modifying the target object.
  • Use same methods for every kind of target/object/event.
  • Easy to understand what the code does.
  • Event target is usually the object itself which makes event bubbling more logical.
  • Popular.

Cons

  • Favors inheritance over composition.
  • Uses strings to identify event types, prone to typo errors and auto-complete doesn't work properly.
  • Event handlers usually accept only a single parameter (Event Object).
    • If you want to pass extra data you have to create a custom event object that implements proper interface or extends a base Event object, a process that is usually bureaucratic and awkward.

Publish / Subscribe (pub/sub)

  • Uses a single object to broadcast messages to multiple subscribers.
    • Not really a prerequisite but most implementations uses a static centralized object as the broadcaster.
  • Use strings to identify the event type.
  • There is no relationship between the message and the target of the event.

Code sample

  globalBroadcaster.subscribe('myCustomEventTypeString', handler);
  globalBroadcaster.publish('myCustomEventTypeString', param1, param2, ...);
  globalBroadcaster.unsubscribe('myCustomEventTypeString', handler);

Pros

  • Any object can publish/subscribe to any event type.
  • Lightweight.
  • Easy to use / implement.

Cons

  • Any object can publish/subscribe to any event type. (yeap, it's pro and con at the same time)
  • Uses strings to identify event types.
    • Error prone.
    • No code-completion (unless you store the value as a variable/constant).
    • Relies on naming conventions to avoid that the message gets intercepted by the wrong subscriber.

Signals

  • Each event type has its own controller.
  • Doesn't rely on strings for event types.

Code sample

  myObject.myCustomEventType.add(handler);
  myObject.myCustomEventType.dispatch(param1, param2, ...);
  myObject.myCustomEventType.remove(handler);

Pros

  • Doesn't rely on strings.
    • Code-completion works properly.
    • Trying to dispatch or listen to an event type that doesn't exist throws errors (helps you find errors early).
    • No need to create constants to store string values.
  • Granular control over each listener and event type.
    • Each signal is already a specific target/container.
  • Easy to identify which signals the object dispatch.
  • Favor composition over inheritance.
    • Doesn't mess with the prototype chain.

Cons

  • Can't dispatch arbitrary events. (which is also a pro in most cases)
  • Each event-type is an object member. (which is also a pro in most cases)
    • Can help to clutter the namespace if you have multiple event types.
  • Doesn't pass the event type and event target to callbacks making it harder to use generic handlers (that works for multiple event types and targets).
  • Is different from what most people are used to.

Conclusion

As most things in life each solution has its pros and cons. It's your task to decide which approach fits better what you are trying to accomplish. I hope this information helps you on your decision. No solution is perfect for all cases.

Back to Home