Wie man einen Mediator mit ES6 erstellt

Einen Mediator einzusetzen, ist immer dann sinnvoll, wenn man eine enge Kopplung von Komponenten vermeiden möchte, aber trotzdem eine Kommunikation zwischen eben jenen notwendig ist. Einen Mediator zu schreiben ist nicht schwierig. Ich zeige Euch heute anhand eines PubSub-Services, wie man einen solchen mit ein paar Zeilen Code definieren kann.

Ein PubSub-Service, als Variante eines Vermittlers, stellt eine Reihe von Kanälen (channels) zur Verfügung. Komponenten können Callbacks registrieren (subscribe), die auf Nachrichten in diesem Kanal lauschen. Nachrichten können von anderen Komponenten im Kanal veröffentlicht werden (publish). Komponenten entscheiden dann selbst mittels Ihrer Callbacks, ob und wie sie auf eine Nachricht reagieren. Wenn die Komponente nicht mehr benötigt wird oder aus anderen Gründen kein "Interesse" mehr an den Ereignissen in einem Kanal hat, kann sie sich vom Kanal abmelden (unsubscribe).

In ECMAScript 6 kann man einen solchen Service als Klasse definieren. Die Kanäle sind dann eine Eigenschaft der Klasse. Die oben erwähnten Funktionen sind Methoden eben dieser Klasse. Eine entsprechende Klasse kann dann wie folgt aussehen:

class Pubsub {

  constructor() {
    this.channels = {};
  }

  subscribe(name, callback) {
    if (!this.channels[name]) {
      this.channels[name] = [];
    }

    this.channels[name].push(callback);
  }

  unsubscribe(name, callback) {
    if (typeof channels[name] !== 'undefined') {
      let channel = [];
      for (let i = 0, len = channels[id].length; i < len; i++) {
        if (channels[id][i] !== callback) {
          channel.push(channels[id][i]);
        }
      }

      channels[id] = channel;
    }
  }

  publish(name, ...params) {
    if (typeof channels[name] !== 'undefined') {
      for (let i = 0, len = channels[name].length; i < len; i++) {
        channels[name][i](...params);
      }
    }
  }

}

Einen neuen Service können wir dann wie folgt initialisieren:

const pubsub = new Pubsub();

Zusätzlich erstellen wir uns einen Callback. Dieser tut nichts anderes, als die erhaltenen Nachrichten in der Konsole auszugeben:

const myCallback = function(message) {
  console.log(message);
};

Mit subscribe können wir dann einen neuen Kanal eröffnen und unseren Callback sogleich im selben registrieren. Wenn wir nun eine Nachricht veröffentlichen wird diese Erwartungsgemäß in der Konsole ausgegeben.

pubsub.subscribe('my channel', myCallback);
pubsub.publish('my channel', 'Nie rufst Du zurück...');
// Ergebnis => "Nie rufst Du zurück..."

Wenn wir nicht mehr auf die Nachrichten im Kanal reagieren wollen, können wir den Callback über unsubscribe wieder aus dem Kanal löschen. Am besten speichert Ihr Euch den Callback (unter Umständen auch zusammen mit dem this-Kontext!) in einer Variable zwischen. Sonst kann die Funktion eventuell hinterher nicht mehr eindeutig zugeordnet und damit dann auch nicht mehr gelöscht werden.

pubsub.unsubscribe('my channel', myCallback);
pubsub.publish('my channel', 'Nie rufst Du zurück...');
// Ergebnis: Keine Ausgabe

Oben erhalten wir dann keine Reaktion mehr auf unsere veröffentlichte Nachricht. Ein Mediator ist eine schöne Sache, birgt aber einige Risiken. Zum einen läuft irgendwann relativ viel Kommunikation über einzelnen Punkt. Zum anderen ist die Reihenfolge von subscribe und publish entscheidend. Wenn eine Komponente etwas veröffentlicht, eine andere aber noch nicht darauf lauscht, kann einen das schonmal einiges an Debugging-Zeit kosten (Race Condition).


Kommentare


Wichtig: Durch den Click auf die obige Checkbox stimmst Du ausdrücklich der Übertragung von Daten an Facebook zu. Die Zustimmung erfolgt einmalig für die Kommentare dieses Artikels und wird nicht gespeichert. Weitere Details kannst Du dem Punkt Social Plugins der Datenschutzerklärung entnehmen.