Что это такое
Паттерн Команда (Command) превращает действие в значение: объект, который умеет выполнять себя — а часто и отменять себя. Действия-значения можно хранить в списках, ставить в очередь, откладывать, записывать в журнал и воспроизводить повторно.
Как только вам нужна отмена, вам нужны команды: что-то должно помнить, что было сделано, чтобы сделать обратное.
Пример: ввод текста с отменой
Каждое слово, добавленное в документ, — это команда с методами execute() и undo(). Выполненные команды попадают в список истории — отмена сводится к тому, чтобы попросить последнюю команду обратить своё действие.
Действия, которые умеют отменять себя
Опечатка «wrold» удаляется не специальным кодом, а той самой командой, которая её добавила, — только она точно знает, что нужно убрать.
Вывод: полная программа на Python
from dataclasses import dataclass
from typing import Protocol
class Command(Protocol):
def execute(self) -> None: ...
def undo(self) -> None: ...
@dataclass
class AddText:
doc: list[str]
text: str
def execute(self) -> None:
self.doc.append(self.text)
def undo(self) -> None:
self.doc.pop()
doc: list[str] = []
history: list[Command] = []
for word in ["Hello", "wrold"]:
cmd = AddText(doc, word)
cmd.execute()
history.append(cmd)
print("документ: ", doc)
# Последняя команда знает, как отменить своё действие.
last = history[-1]
last.undo()
print("после отмены:", doc)
Когда использовать
Используйте его для отмены/повтора, очередей действий, макросов и журналов аудита — везде, где действия нужно хранить или отменять.
Не используйте его, когда действия выполняются и забываются. В Python простое действие в очереди — это часто просто функция, добавленная в список; полный паттерн оправдывает себя, только когда нужна отмена или просмотр действий.
Плюсы и минусы
Плюсы: отмена/повтор получаются естественно; действия можно ставить в очередь, записывать в журнал и воспроизводить; новые действия подключаются без изменения вызывающего объекта.
Минусы: по одному классу на каждое действие — их быстро становится много; правильно сохранить состояние для отмены непросто — команда должна запомнить всё, что нужно, чтобы отменить себя.