Das Command Pattern ist ein bekanntes Software-Entwurfsmuster, das Befehle als eigenständige Objekte behandelt. Dabei geht es nicht nur um das Ausführen einer Funktion, sondern auch um das Kapseln aller relevanten Informationen wie Empfänger, Methode und Parameter. Entwickler:innen können so einzelne Aktionen in Objekte verpacken und flexibel aufrufen, protokollieren oder sogar rückgängig machen. In JavaScript stößt man auf dieses Muster vor allem bei der Organisation komplexer Abläufe und bei Situationen, in denen eine Undo/Redo-Funktionalität benötigt wird. Die grundlegende Idee, jegliche Aktionen zu abstrahieren und ihnen eine gemeinsame Struktur zu geben, erhöht die Wartbarkeit und Erweiterbarkeit des Codes erheblich. Dieser Blogpost beleuchtet sowohl die Vorteile als auch die Nachteile des Command Patterns und zeigt Dir anhand praktischer Beispiele, wie Du es in JavaScript sinnvoll nutzen kannst.
Was ist das Command Pattern?
Das Command Pattern verfolgt das Ziel, eine Aktion oder einen Befehl in ein eigenständiges Objekt zu verpacken. Hinter diesem Objekt verbergen sich sämtliche Informationen darüber, wie, wann und warum eine bestimmte Operation ausgeführt werden soll. Für JavaScript bedeutet das: Wir schreiben eine Funktion bzw. mit dem ES6-Ansatz eine Klasse, die genau festlegt, was passieren soll, wenn wir den Befehl aufrufen. Dieses Objekt kann dann in einer Variablen gespeichert, an andere Komponenten weitergegeben oder in eine Befehlswarteschlange eingereiht werden.
Der Charme dieses Konzepts liegt in seiner klaren Schnittstelle und hohen Flexibilität. Weil der Befehl im Objekt gekapselt ist, müssen sich andere Teile des Programms nicht um die Details kümmern. Sie wissen lediglich, dass dort etwas “ausführbar” ist. Gerade in großen JavaScript-Anwendungen, in denen viele unterschiedliche Komponenten zusammenspielen, schafft das Command Pattern so Übersicht und klare Verantwortlichkeiten.
Funktionsweise und Kernbestandteile
In JavaScript werden Objekte gerne genutzt, um Daten und Methoden zu gruppieren. Für das Command Pattern reicht es dabei im Grunde aus, wenn man sich an die folgenden Kernpunkte hält:
- Befehlsschnittstelle: Jedes Command-Objekt sollte eine Methode haben, zum Beispiel
execute()
, die genau definiert, was beim Aufruf passieren soll. - Empfänger (Receiver): Dieses Objekt oder Modul führt letztlich die Aktion aus. Es enthält die eigentliche Logik, zum Beispiel eine Funktion zum Senden einer HTTP-Anfrage oder zum Updaten der UI.
- Invoker: Dies ist meist eine Komponente, die den Befehl anstößt und ausführt. Im Browser-Umfeld kann das zum Beispiel ein Button sein, der bei Klick das Command-Objekt aufruft.
Die Trennung dieser Verantwortlichkeiten ist einer der Hauptgründe, warum das Command Pattern so beliebt ist. Die Kapselung macht es zudem einfach, einen Befehl zu protokollieren oder rückgängig zu machen, da jeder Befehl genau weiß, wie er sich ausführen oder widerrufen lässt.
Ein einfaches Codebeispiel mit Ausführen und Rückgängig machen
Um das Command Pattern in JavaScript besser zu illustrieren, möchten wir uns das Command Pattern an Hand eines einfachen Taschenrechners anschauen.
Einfacher Taschenrechner als ES6 Klasse
Hierzu möchte ich den Taschenrechner erst einmal als normale ES6-Klasse vorstellen, wie wir sie schreiben würden, wenn wir ohne das Command Pattern auskommen wollten.
class Calculator {
constructor() {
this.value = 0;
}
add(valueToAdd) {
return this.value = this.value + valueToAdd;
}
subtract(valueToSubtract) {
return this.value = this.value - valueToSubtract;
}
multiply(valueToMultiply) {
return this.value = this.value * valueToMultiply;
}
divide(valueToDivide) {
return this.value = this.value / valueToDivide;
}
}
// Nutzungsteil
const calculator = new Calculator();
let newVal = calculator.add(10); // 10
newVal = calculator.subtract(5); // 5
Das aktive Codebeispiel zeigt die Implementierung einer einfachen Calculator-Klasse in JavaScript. Diese Klasse bietet grundlegende arithmetische Operationen wie Addition, Subtraktion, Multiplikation und Division.
Der Konstruktor der Calculator-Klasse initialisiert eine Eigenschaft value mit dem Wert 0. Diese Eigenschaft speichert den aktuellen Wert des Rechners.
Diese Calculator-Klasse ermöglicht es, eine Reihe von arithmetischen Operationen auf einem internen Wert durchzuführen, der durch die Methoden add, subtract, multiply und divide manipuliert wird. Dies ist ein einfaches Beispiel für eine Klasse, die Zustand und Verhalten kombiniert, um eine nützliche Funktionalität bereitzustellen.
Im Nutzungsteil des Codes wird eine Instanz der Calculator-Klasse erstellt. Die Methode add wird aufgerufen, um 10 zum aktuellen Wert hinzuzufügen, was das Ergebnis 10 liefert. Anschließend wird die Methode subtract aufgerufen, um 5 vom aktuellen Wert abzuziehen, was das Ergebnis 5 liefert.
Einfacher Taschenrechner im Command Pattern
Wenn wir unseren Taschenrechner mit dem Command Pattern realisieren wollen, erstellen wir als erstes das Command-Objekt für den Calculator, dem wir die Methoden constructor, execute und undo mitgeben. Die Methoden für die einzelen Rechenschritte gliedern wir in jeweils einzelne Klassen aus.
Zur Veranschaulichung erzeugen wir hier zuerst einmal lediglich die Methode zur Addition als Klasse mit dem Namen AddCommand. Diese besteht ebenfalls aus den Methoden constructor, execute und undo. Im Gegensatz zum Command-Objekt enthalten diese execute und undo Methoden jedoch die tatsächlichen Arbeitsschritte der jeweiligen Rechnungen.
class Calculator {
constructor() {
this.value = 0;
this.history = [];
}
execute(command) {
this.history.push(command);
return this.value = command.execute(this.value);
}
undo() {
const command = this.history.pop();
return this.value = command.undo(this.value);
}
}
class AddCommand {
constructor(valueToAdd) {
this.valueToAdd = valueToAdd;
}
execute(currentValue) {
return currentValue + this.valueToAdd;
}
undo(currentValue) {
return currentValue - this.valueToAdd;
}
}
Das aktive Codebeispiel zeigt die Implementierung des Befehlsmusters (Command Pattern) in JavaScript. Das Befehlsmuster ist ein Verhaltensmuster, das eine Anforderung in ein eigenständiges Objekt kapselt, wodurch Parameter für die Anforderung sowie die Operationen zum Rückgängigmachen der Anforderung gespeichert werden können.
Die Klasse Calculator repräsentiert den Empfänger, der die Befehle ausführt. Im Konstruktor werden zwei Eigenschaften initialisiert: value, das den aktuellen Wert des Rechners speichert, und history, ein Array, das die Historie der ausgeführten Befehle speichert.
Die Methode execute nimmt ein Befehlsobjekt als Argument entgegen, führt dessen execute-Methode aus und aktualisiert den aktuellen Wert des Rechners. Der Befehl wird anschließend zur Historie hinzugefügt. Die Methode undo entfernt den zuletzt ausgeführten Befehl aus der Historie und führt dessen undo-Methode aus, um den vorherigen Zustand wiederherzustellen.
Die Klasse AddCommand repräsentiert einen konkreten Befehl, der eine Addition durchführt. Im Konstruktor wird der Wert valueToAdd initialisiert, der zum aktuellen Wert des Rechners hinzugefügt werden soll. Die Methode execute nimmt den aktuellen Wert des Rechners als Argument entgegen und gibt die Summe des aktuellen Werts und valueToAdd zurück. Die Methode undo nimmt den aktuellen Wert des Rechners als Argument entgegen und gibt die Differenz des aktuellen Werts und valueToAdd zurück.
Dieses Beispiel zeigt, wie das Befehlsmuster verwendet werden kann, um Operationen auf einem Rechner zu kapseln und eine Historie der ausgeführten Befehle zu verwalten. Dies ermöglicht es, Operationen rückgängig zu machen und den Zustand des Rechners auf einfache Weise zu verwalten.
Erweitern des Taschenrechners mit dem Command Pattern
Ein großer Vorteil des Command Patterns ist es, dass wir unseren Taschenrechner ganz einfach durch weitere Befehle erweitern können. Hier erweitern wir z.B. die Möglichkeit Substraktionen durchzuführen. Die dazu notwendige Klasse SubstractCommand besteht auch hier wieder aus den Methoden constructor, execute und undo.
class SubtractCommand {
constructor(valueToSubtract) {
this.valueToSubtract = valueToSubtract;
}
execute(currentValue) {
return currentValue - this.valueToSubtract;
}
undo(currentValue) {
return currentValue + this.valueToSubtract;
}
}
Das aktive Codebeispiel zeigt die Implementierung einer SubtractCommand-Klasse in JavaScript, die Teil des Befehlsmusters (Command Pattern) ist. Diese Klasse repräsentiert einen konkreten Befehl, der eine Subtraktion durchführt und die Möglichkeit bietet, diese Operation rückgängig zu machen.
Der Konstruktor der SubtractCommand-Klasse initialisiert eine Eigenschaft valueToSubtract, die den Wert speichert, der vom aktuellen Wert des Rechners subtrahiert werden soll.
Die Methode execute nimmt den aktuellen Wert des Rechners als Argument entgegen und gibt die Differenz des aktuellen Werts und valueToSubtract zurück. Diese Methode führt die eigentliche Subtraktionsoperation aus.
Die Methode undo nimmt ebenfalls den aktuellen Wert des Rechners als Argument entgegen und gibt die Summe des aktuellen Werts und valueToSubtract zurück. Diese Methode macht die Subtraktionsoperation rückgängig, indem sie den subtrahierten Wert wieder hinzufügt.
Diese SubtractCommand-Klasse ermöglicht es, Subtraktionsoperationen auf einem Rechner zu kapseln und eine Historie der ausgeführten Befehle zu verwalten. Dies ist besonders nützlich in Kombination mit einer Calculator-Klasse, die das Befehlsmuster verwendet, um Operationen auszuführen und rückgängig zu machen.
Kombinieren von Befehlen mit dem Command Pattern
Doch wir können nicht nur einfach Befehle ergänzen, sondern auch kombinierte Befehlketten als einzelen Befehl zu unserem Command-Objekt hinzufügen. Diese stehen uns dann mit nur einem einzelnen Befehlsaufruf zur Verfügung.
class AddThenSubstractCommand {
constructor(valueToAdd, valueToSubstract) {
this.addCommand = new AddCommand(valueToAdd);
this.substractCommand = new SubtractCommand(valueToSubstract);
}
execute(currentValue) {
const newValue = this.addCommand.execute(currentValue);
return this.substractCommand.execute(newValue);
}
undo(currentValue) {
const newValue = this.substractCommand.undo(currentValue);
return this.addCommand.undo(newValue)
}
}
Das aktive Codebeispiel zeigt die Implementierung einer AddThenSubstractCommand-Klasse in JavaScript, die das Befehlsmuster (Command Pattern) verwendet, um eine Kombination von Additions- und Subtraktionsoperationen zu kapseln. Diese Klasse ermöglicht es, zwei Operationen nacheinander auszuführen und diese auch rückgängig zu machen.
Der Konstruktor der AddThenSubstractCommand-Klasse nimmt zwei Argumente entgegen: valueToAdd und valueToSubstract. Diese Werte werden verwendet, um Instanzen der AddCommand- und SubstractCommand-Klassen zu erstellen, die die jeweiligen Operationen kapseln.
Die Methode execute nimmt den aktuellen Wert des Rechners als Argument entgegen. Zuerst wird die execute-Methode der AddCommand-Instanz aufgerufen, um den Wert zu addieren. Das Ergebnis dieser Operation wird dann an die execute-Methode der SubstractCommand-Instanz übergeben, um den Wert zu subtrahieren. Das Endergebnis wird zurückgegeben.
Die Methode undo nimmt ebenfalls den aktuellen Wert des Rechners als Argument entgegen. Zuerst wird die undo-Methode der SubstractCommand-Instanz aufgerufen, um die Subtraktionsoperation rückgängig zu machen. Das Ergebnis dieser Operation wird dann an die undo-Methode der AddCommand-Instanz übergeben, um die Additionsoperation rückgängig zu machen. Das Endergebnis wird zurückgegeben.
Diese AddThenSubstractCommand-Klasse zeigt, wie das Befehlsmuster verwendet werden kann, um komplexe Operationen zu kapseln und eine Historie der ausgeführten Befehle zu verwalten. Durch die Kombination von Additions- und Subtraktionsoperationen in einer einzigen Klasse wird die Wiederverwendbarkeit und Modularität des Codes erhöht.
Nutzung des so erzeugten Command Patterns
Die Nutzung unseres somit erzeugten Command Patterns mit den Befehlen AddCommand, SubstractCommand und AddThenSubstractCommand würde dann wie folgt aussehen.
const calculator = new Calculator();
let newVal = calculator.execute(new AddCommand(10));
console.log(newVal); // 10
newVal = calculator.execute(new SubtractCommand(5));
console.log(newVal); // 5
newVal = calculator.execute(new AddThenSubstractCommand(50, 20));
console.log(newVal); // 35
newVal = calculator.undo();
console.log(newVal); // 5
newVal = calculator.undo();
console.log(newVal); // 10
Das aktive Codebeispiel zeigt die Nutzung des Befehlsmusters (Command Pattern) in einer Calculator-Klasse, um verschiedene arithmetische Operationen auszuführen und rückgängig zu machen. Die Befehle werden als separate Klassen implementiert und zur Laufzeit an den Rechner übergeben.
Zunächst wird ein neuer Wert newVal durch die Ausführung eines AddCommand-Befehls mit dem Wert 10 berechnet. Die Methode execute der Calculator-Klasse führt den Befehl aus, aktualisiert den internen Wert des Rechners und speichert den Befehl in der Historie. Das Ergebnis, 10, wird in der Konsole ausgegeben.
Anschließend wird ein SubtractCommand-Befehl mit dem Wert 5 ausgeführt. Der aktuelle Wert des Rechners wird um 5 verringert, und das Ergebnis, 5, wird in der Konsole ausgegeben.
Ein AddThenSubstractCommand-Befehl wird mit den Werten 50 und 20 ausgeführt. Dieser Befehl führt zuerst eine Addition von 50 und dann eine Subtraktion von 20 durch. Das Ergebnis, 35, wird in der Konsole ausgegeben.
Die Methode undo der Calculator-Klasse wird aufgerufen, um den zuletzt ausgeführten Befehl rückgängig zu machen. In diesem Fall wird der AddThenSubstractCommand rückgängig gemacht, was den Wert des Rechners auf 5 zurücksetzt. Das Ergebnis wird in der Konsole ausgegeben.
Ein weiterer Aufruf der Methode undo macht den SubtractCommand rückgängig, was den Wert des Rechners auf 10 zurücksetzt. Auch dieses Ergebnis wird in der Konsole ausgegeben.
Dieses Beispiel zeigt, wie das Befehlsmuster verwendet werden kann, um arithmetische Operationen zu kapseln, eine Historie der ausgeführten Befehle zu verwalten und Operationen rückgängig zu machen. Dies ermöglicht eine flexible und erweiterbare Architektur für den Rechner.
Vorteile des Command Patterns
Eines der größten Argumente für das Command Pattern ist die Klarheit: Befehle werden als eigenständige Einheiten behandelt, die man verschieben, speichern und manipulieren kann. Das erleichtert besonders den Umgang mit komplexen Abläufen, in denen man später auf Befehle zugreifen möchte, um sie erneut auszuführen oder rückgängig zu machen.
Aufgrund der klaren Schnittstelle wird das System außerdem erweiterbar. Sobald eine neue Funktion hinzukommt, muss nur ein weiterer Command geschrieben werden, der sich an dasselbe Interface hält. Für Entwickler:innen ist das im Teamalltag eine enorme Erleichterung, da man sich auf eine einheitliche Struktur verlassen kann.
Ein weiterer Pluspunkt ist das zentrale Logging. Da jeder Befehl ein eigenes Objekt repräsentiert, kann man das Objekt sehr einfach in einer Liste oder Historie speichern. Gerade bei Undo/Redo-Mechanismen ist das Command Pattern nahezu unschlagbar, weil es sich quasi von selbst um die Rückabwicklung kümmert, sofern man eine passende undo()
-Methode im Command vorgesehen hat.
Nachteile des Command Patterns
Obwohl das Command Pattern viele Vorteile bietet, ist es nicht immer die beste Wahl. Wenn Deine Anwendung nur sehr einfache Abläufe hat, kann die zusätzliche Abstraktion den Code unnötig aufblähen. Auch kann es in JavaScript ein wenig umständlich wirken, ständig Klassen oder Konstruktorfunktionen für jede Aktion zu definieren. Manchmal reicht eine schlichte Funktion vollkommen aus.
Zudem muss man sich beim Design genau überlegen, wie das Undo/Redo oder ein generisches Logging aussehen soll. Denn zwar legt das Command Pattern die Basis dafür, erfordert jedoch auch Disziplin von den Entwickler:innen, jede Aktion im passenden Command-Objekt zu kapseln. Die damit verbundene Lernkurve kann, besonders für Einsteiger:innen, anfangs abschreckend wirken.
Fazit
Das Command Pattern bietet in JavaScript eine klare Struktur, um komplexe Abläufe zu organisieren und Aktionen unabhängig voneinander zu verwalten. Besonders in Szenarien, in denen Undo/Redo-Funktionalität oder eine zentrale Befehlsverwaltung gefragt ist, spielt es seine Stärken voll aus. Es hat jedoch auch eine gewisse Komplexität, die nicht in jeder Anwendung nötig ist. Für große Projekte oder anspruchsvolle Teamarbeit lohnt es sich aber, dieses Muster genauer unter die Lupe zu nehmen und einzusetzen. Die Beispiele in diesem Beitrag zeigen, wie sich das Muster nahtlos in die JavaScript-Welt einfügt, wo Objekte durch ihre flexible Natur genau für solche Design Patterns prädestiniert sind. Dank klar definierter Methoden wie execute()
oder undo()
können Entwickler:innen ihre Anwendungen sauber strukturieren und ihren Code langfristig pflegen.
FAQ – Häufig gestellte Fragen zum Command Pattern in JavaScript
-
Was ist der wichtigste Vorteil des Command Patterns?
Der größte Vorteil ist die saubere Kapselung von Befehlen. Aktionen (Befehle) lassen sich als eigenständige Objekte verwalten und damit flexibel speichern, weitergeben oder rückgängig machen. Ein einfaches Beispiel:class SimpleCommand { constructor(receiver, value) { this.receiver = receiver; this.value = value; this.prevValue = receiver.state; } execute() { this.receiver.update(this.value); } undo() { this.receiver.update(this.prevValue); } }
-
Wie füge ich eine Undo-Funktion hinzu?
Indem Du in Deinem Command-Objekt eineundo()
-Methode definierst, die auf den Ursprungszustand zurückgreift. Im oben gezeigten Beispiel hältst Du den alten Wert in einer Variablen wieprevValue
fest und setzt ihn imundo()
-Aufruf zurück.// ... undo() { this.receiver.setState(this.prevValue); }
-
Lohnt es sich, das Command Pattern in kleinen Projekten einzusetzen?
Oft ist der Nutzen für sehr einfache Anwendungen gering, da Du eine zusätzliche Abstraktionsschicht einführst. Wenn Du allerdings bereits absehen kannst, dass Undo/Redo-Funktionen oder die Kapselung von Aktionen benötigt wird, kann es sich durchaus lohnen.// In kleinen Projekten oft noch einfach genug: function simpleAction() { console.log("Ich führe eine einfache Aktion aus"); }
-
Welche Rolle spielt der sogenannte Invoker?
Der Invoker ist das Objekt, das den Befehl ausführt. In Browser-Anwendungen kann das zum Beispiel ein Klick-Event sein, das ein Command-Objekt anstößt.document.querySelector('#myButton').addEventListener('click', () => { const command = new SimpleCommand(myReceiver, 'Neue Daten'); command.execute(); });
-
Kann ich das Command Pattern auch mit asynchronen Operationen verwenden?
Ja, natürlich. Command-Objekte können Promises oderasync/await
nutzen. Wichtig ist nur, dass Du Deineexecute()
-Methode entsprechend anpasst.class AsyncCommand { async execute() { const data = await fetch('https://api.example.com/data'); // Weiterverarbeitung } }
-
Wie kann ich mehrere Befehle in einer Transaktion ausführen?
Du kannst mehrere Commands nacheinander aufrufen und sie in einer Gruppe oder Liste verwalten. So hast Du eine Art “Transaktion” aus mehreren Einzelschritten, die Du komplett ausführen oder rückgängig machen kannst.const transactionCommands = [cmd1, cmd2, cmd3]; transactionCommands.forEach(cmd => cmd.execute()); // ... transactionCommands.reverse().forEach(cmd => cmd.undo());
-
Ist das Command Pattern eine gute Wahl für Logging und Analyse?
Ja, denn jedes Command-Objekt lässt sich vor oder nach dem Ausführen loggen. Du kannst gezielt Informationen abspeichern, was wann und von wem ausgeführt wurde.function runCommandWithLogging(command) { console.log('Command wird ausgeführt:', command.constructor.name); command.execute(); console.log('Command beendet:', command.constructor.name); }
-
Wie vermeide ich, dass zu viele Command-Klassen entstehen?
Achte auf ein sinnvolles Zusammenfassen von ähnlichen Aktionen. Manchmal genügt auch eine Parameterübergabe, statt für jede Variation eine eigene Klasse zu schreiben.class UpdateCommand { constructor(receiver, type, payload) { this.receiver = receiver; this.type = type; this.payload = payload; } execute() { this.receiver.update(this.type, this.payload); } }
-
Kann ich das Command Pattern auch ohne Klassen einsetzen?
Auf jeden Fall. JavaScript ist sehr flexibel, Du kannst stattdessen einfache Funktionen oder Object-Literals verwenden, die sich an dieselbe Struktur halten.const command = { execute: () => console.log("Command ausgeführt"), undo: () => console.log("Command rückgängig gemacht") }; command.execute(); command.undo();
-
Welche typischen Fehler machen Entwickler:innen häufig beim Einsatz des Command Patterns und wie kann man sie vermeiden?
Ein häufiger Fehler ist, dass Entwickler:innen vergessen, den ursprünglichen Zustand korrekt zu speichern, um eine Undo-Funktion zu ermöglichen. Das kann dazu führen, dass derundo()
-Aufruf nicht zum erwarteten Ausgangswert zurückkehrt. Ebenso oft wird der Geltungsbereich für lokale Variablen fehlerhaft gewählt, was zu unvorhersehbaren Seiteneffekten führen kann. Darüber hinaus vernachlässigen manche das Logging oder halten ihre Commands zu generisch – so wird das Muster schwer wartbar.Ein kleines Negativbeispiel verdeutlicht einen solchen Fehler:
class Calculator { constructor() { this.value = 0; } add(operand) { this.value += operand; } } class AddCommand { constructor(calculator, operand) { this.calculator = calculator; this.operand = operand; // Fehler: previousValue wird nicht gespeichert } execute() { this.calculator.add(this.operand); } undo() { // Fehler: Kein Zugriff auf den ursprünglichen Zustand // -> Kann den Wert nicht zurücksetzen console.error('undo() kann nicht ausgeführt werden, da kein vorheriger Wert gespeichert wurde.'); } } // Verwendung const calc = new Calculator(); const faultyCommand = new AddCommand(calc, 10); faultyCommand.execute(); console.log(calc.value); // 10 // Undo funktioniert nicht faultyCommand.undo(); // Gibt Fehlermeldung aus console.log(calc.value); // 10 bleibt erhalten, ist nicht rückgängig gemacht
Um solche Fehler zu vermeiden, ist es essenziell, den alten Zustand innerhalb des Command-Objekts abzuspeichern, damit
undo()
diesen verlässlich wiederherstellen kann. So wird das Command Pattern zuverlässig und entfaltet seinen vollen Nutzen.
Damit solltest Du einen fundierten Überblick über das Command Pattern in JavaScript haben. Es lohnt sich, dieses Muster gerade bei komplexeren Vorhaben in Betracht zu ziehen. Viel Erfolg bei der Umsetzung!
Buy me a coffee
Wenn Dir meine Beiträge gefallen und sie Dir bei Deiner Arbeit helfen, würde ich mich über einen “Kaffee” und ein paar nette Worte von Dir freuen.