Command pattern (или шаблон команд) — это поведенческий паттерн проектирования, который превращает запросы или простые операции в объекты. Он используется для инкапсуляции всех сведений, необходимых для выполнения действия, включая метод, параметры и объект. В контексте JavaScript и библиотеки Vex Command Pattern помогает организовать выполнение действий пользователя в виде независимых объектов, что упрощает их обработку и повторное использование.
Шаблон Command представляет собой объект, который инкапсулирует все данные, связанные с конкретным действием. Этот объект обычно состоит из нескольких элементов:
Для реализации шаблона команд в JavaScript можно использовать простую структуру объектов и классов. Рассмотрим пример, где приёмником будет объект, управляющий состоянием интерфейса, а команда — это действие пользователя.
Интерфейс команды содержит метод execute(), который
будет вызван для выполнения действия.
class Command {
execute() {
throw new Error('Метод execute должен быть реализован');
}
}
Каждая команда будет реализовывать интерфейс Command и
предоставлять конкретную реализацию метода execute.
Например, команда для включения и выключения света.
class LightOnCommand extends Command {
constructor(light) {
super();
this.light = light;
}
execute() {
this.light.turnOn();
}
}
class LightOffCommand extends Command {
constructor(light) {
super();
this.light = light;
}
execute() {
this.light.turnOff();
}
}
Приёмник — это объект, который фактически выполняет операцию. В нашем
случае это будет объект Light, управляющий состоянием
света.
class Light {
turnOn() {
console.log('Свет включён');
}
turnOff() {
console.log('Свет выключён');
}
}
Invoker будет хранить и запускать команды. Он должен быть способен передавать команды для выполнения в ответ на действия пользователя.
class RemoteControl {
constructor() {
this.command = null;
}
setCommand(command) {
this.command = command;
}
pressButton() {
this.command.execute();
}
}
Клиент создаёт объекты команд и связывает их с приёмниками. В данном примере создаются конкретные команды для управления светом и настраивается пульт управления.
const light = new Light();
const lightOn = new LightOnCommand(light);
const lightOff = new LightOffCommand(light);
const remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton(); // Свет включён
remote.setCommand(lightOff);
remote.pressButton(); // Свет выключён
Для добавления функционала отмены и повтора операций (undo/redo)
нужно добавить поддержку истории команд в объект Invoker.
История будет хранить выполненные команды, и их можно будет повторно
вызвать в случае необходимости.
class RemoteControlWithUndo {
constructor() {
this.command = null;
this.history = [];
}
setCommand(command) {
this.command = command;
}
pressButton() {
this.command.execute();
this.history.push(this.command);
}
undo() {
const command = this.history.pop();
console.log('Отменено:');
command.undo();
}
}
class LightOnCommandWithUndo extends LightOnCommand {
undo() {
this.light.turnOff();
}
}
class LightOffCommandWithUndo extends LightOffCommand {
undo() {
this.light.turnOn();
}
}
Использование Command Pattern в JavaScript позволяет эффективно управлять действиями пользователя, инкапсулируя запросы в объекты, что упрощает их обработку, добавление новых команд и управление состоянием. В библиотеке Vex, где часто требуются динамичные взаимодействия с пользователем, этот паттерн помогает создать гибкую и расширяемую архитектуру, минимизируя зависимость между различными частями приложения.