Шаблон Command: инкапсуляция действий
Оборачивайте запросы в объекты Command для поддержки отмены, повтора и записи макрокоманд.
«Шаблон Command: инкапсуляция действий» — бесплатный урок Java Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.
Назначение Command
Command инкапсулирует запрос как объект, позволяя параметризовать клиентов различными запросами, ставить их в очередь, вести журналирование и выполнять операции с возможностью отмены.
Интерфейс Command
Определите интерфейс с методом execute() и, при необходимости, методом undo(). Каждый объект команды знает, как выполнить и отменить одно действие.
public interface Command {
void execute();
void undo();
}Конкретная команда: TextEditor
Каждая конкретная команда инкапсулирует получателя и параметры действия. Выполнение осуществляет действие, а отмена возвращает систему в предыдущее состояние.
public class InsertTextCommand implements Command {
private final TextEditor editor;
private final String text;
private final int position;
public InsertTextCommand(TextEditor editor, String text, int pos) {
this.editor = editor; this.text = text; this.position = pos;
}
public void execute() { editor.insert(position, text); }
public void undo() { editor.delete(position, text.length()); }
}Вызывающий объект: CommandHistory
Вызывающий объект хранит историю выполненных команд. Он вызывает execute() и помещает команду в стек. Отмена извлекает команду из стека и вызывает undo().
public class CommandHistory {
private final Deque<Command> history = new ArrayDeque<>();
public void execute(Command cmd) {
cmd.execute();
history.push(cmd);
}
public void undo() {
if (!history.isEmpty()) history.pop().undo();
}
}Стек отмены и повтора
Добавьте стек повтора: при отмене помещайте команду в стек повтора, а при повторе извлекайте её из стека повтора и выполняйте снова.
private final Deque<Command> undoStack = new ArrayDeque<>();
private final Deque<Command> redoStack = new ArrayDeque<>();
public void redo() {
if (!redoStack.isEmpty()) {
Command cmd = redoStack.pop();
cmd.execute();
undoStack.push(cmd);
}
}Макрокоманда
Макрокоманда — это составная команда, содержащая список команд и выполняющая их последовательно. Для отмены выполняются обратные действия в обратном порядке.
public class MacroCommand implements Command {
private final List<Command> commands;
public MacroCommand(List<Command> commands) { this.commands = commands; }
public void execute() { commands.forEach(Command::execute); }
public void undo() { for (int i = commands.size()-1; i>=0; i--) commands.get(i).undo(); }
}Очередь команд для обработки задач
Храните команды в очереди и обрабатывайте их асинхронно. Рабочий поток извлекает команды из очереди и выполняет их, отделяя производителей от потока выполнения.
BlockingQueue<Command> queue = new LinkedBlockingQueue<>();
// Producer:
queue.put(new SendEmailCommand(recipient, subject, body));
// Consumer thread:
Command cmd = queue.take();
cmd.execute();Команда с исполнителем
Оберните команды в лямбда-выражения Runnable и передайте их в ExecutorService — лямбда-выражение и есть объект команды.
ExecutorService exec = Executors.newFixedThreadPool(4);
exec.submit(() -> sendEmail(recipient, subject));
exec.submit(() -> generateReport(params));Журналирование команд для аудита
Сериализуемые объекты Command можно сохранять в журнале. При восстановлении воспроизведите их, чтобы воссоздать конечное состояние — это основа источника событий.
void execute(Command cmd) {
cmd.execute();
auditLog.append(cmd.toString()); // log every action
history.push(cmd);
}Кнопки действий GUI
В средах разработки GUI каждая кнопка или пункт меню содержит объект Command. Нажатие кнопки вызывает command.execute(). Заменяйте команды во время выполнения, чтобы изменять поведение кнопок.
Button saveBtn = new Button("Save");
saveBtn.setOnAction(() -> new SaveDocumentCommand(doc).execute());Command и стратегия
Оба паттерна инкапсулируют поведение. Стратегия инкапсулирует алгоритм, который можно заменять во время выполнения. Command инкапсулирует полный запрос, включая его параметры и получателя, и поддерживает историю и постановку в очередь.
Command в Spring
Tasklet в Spring Batch и MessageHandler в Spring Integration — это паттерны Command на уровне приложения. Каждый Tasklet инкапсулирует один шаг пакетного задания.
Быстрая проверка
Какой дополнительный метод добавляет Command помимо execute(), чтобы поддержать отмену?
Повторение
Command инкапсулирует действия в виде объектов. Используйте его для стеков отмены и повтора, очередей задач, записи макрокоманд и журналирования аудита. Сочетайте его с вызывающим объектом, который ведёт историю команд.
Часто задаваемые вопросы
Урок «Шаблон Command: инкапсуляция действий» бесплатный?
Да — полный текст урока «Шаблон Command: инкапсуляция действий» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.
Чему я научусь в уроке «Шаблон Command: инкапсуляция действий»?
Оборачивайте запросы в объекты Command для поддержки отмены, повтора и записи макрокоманд. Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Java Academy?
Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Шаблон Command: инкапсуляция действий»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Java Academy?
Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Шаблон Observer: уведомление о событиях
- Шаблон Strategy: взаимозаменяемые алгоритмы
- Шаблон Command: инкапсуляция действий
- Шаблон Template Method: каркасы алгоритмов