Что это такое
Паттерн Command превращает действие в значение: в объект, который знает, как себя выполнить — и часто как себя отменить. Действия-значения можно хранить в массивах, ставить в очередь, откладывать, записывать в журнал и воспроизводить заново.
Как только вам нужна отмена, вам нужны команды: что-то должно помнить, что было сделано, чтобы сделать обратное.
Пример: набор текста с отменой
Каждое слово, добавленное в документ, — это команда с методами execute() и undo(). Выполненные команды попадают в массив истории — отмена сводится к тому, чтобы попросить последнюю из них обратить своё действие.
Действия, которые умеют себя обращать
Опечатка wrold удаляется не специальным кодом, а той командой, которая её добавила, — только она точно знает, что нужно забрать обратно. Каждая команда хранит сам массив документа, поэтому её push и pop меняют документ вызывающего кода.
Вывод: программа на TypeScript и захваченный вывод
interface Command {
execute(): void
undo(): void
}
class AddText implements Command {
private doc: string[]
private text: string
constructor(doc: string[], text: string) {
this.doc = doc
this.text = text
}
execute(): void {
this.doc.push(this.text)
}
undo(): void {
this.doc.pop()
}
}
const doc: string[] = []
const history: Command[] = []
for (const word of ["Hello", "wrold"]) {
const command = new AddText(doc, word)
command.execute()
history.push(command)
}
console.log("документ: ", doc)
// Последняя команда знает, как забрать себя обратно.
const last = history[history.length - 1]
last.undo()
console.log("после отмены:", doc)
Когда его использовать
Используйте его для отмены и повтора действий, очередей действий, макросов и журналов аудита — везде, где действия нужно хранить или обращать.
Откажитесь от него, когда действия выполняются по принципу «запустил и забыл». Поставленное в очередь действие, которое нечего отменять, часто оказывается просто функцией-значением в массиве — полный паттерн оправдывает себя только тогда, когда нужна отмена или изучение действий.
Плюсы и минусы
Плюсы: отмена и повтор становятся естественными; действия можно ставить в очередь, записывать в журнал и воспроизводить заново; новые действия подключаются без изменения вызывающей стороны.
Минусы: по одному классу на действие быстро накапливается; корректное состояние для отмены — тонкий момент: команда должна запомнить всё, что нужно для обращения её действия.