Summer SALE
Команда

Команда на Java

Команда — это поведенческий паттерн, позволяющий заворачивать запросы или простые операции в отдельные объекты.

Это позволяет откладывать выполнение команд, выстраивать их в очереди, а также хранить историю и делать отмену.

Сложность:

Популярность:

Применимость: Паттерн можно часто встретить в Java-коде, особенно когда нужно откладывать выполнение команд, выстраивать их в очереди, а также хранить историю и делать отмену.

Примеры Команд в стандартных библиотеках Java:

Признаки применения паттерна: Классы команд построены вокруг одного действия и имеют очень узкий контекст. Объекты команд часто подаются в обработчики событий элементов GUI. Практически любая реализация отмены использует принципа команд.

Команды текстового редактора и их отмена

По реакции на действия пользователя, текстовый редактор создаёт объекты команд. Каждая команда выполняет некоторое действие, а затем попадают в стек истории.

Теперь, чтобы выполнить отмену, мы берём последнюю команду из списка и выполняем обратное действие либо восстанавливаем состояние редактора, сохранённое в этой команде.

commands

commands/Command.java: Абстрактная базовая комманда

package refactoring_guru.command.example.commands; import refactoring_guru.command.example.editor.Editor; public abstract class Command { public Editor editor; private String backup; Command(Editor editor) { this.editor = editor; } void backup() { backup = editor.textField.getText(); } public void undo() { editor.textField.setText(backup); } public abstract boolean execute(); } 

commands/CopyCommand.java: Команда копирования

package refactoring_guru.command.example.commands; import refactoring_guru.command.example.editor.Editor; public class CopyCommand extends Command { public CopyCommand(Editor editor) { super(editor); } @Override public boolean execute() { editor.clipboard = editor.textField.getSelectedText(); return false; } } 

commands/PasteCommand.java: Команда вставки

package refactoring_guru.command.example.commands; import refactoring_guru.command.example.editor.Editor; public class PasteCommand extends Command { public PasteCommand(Editor editor) { super(editor); } @Override public boolean execute() { if (editor.clipboard == null || editor.clipboard.isEmpty()) return false; backup(); editor.textField.insert(editor.clipboard, editor.textField.getCaretPosition()); return true; } } 

commands/CutCommand.java: Команда вырезания

package refactoring_guru.command.example.commands; import refactoring_guru.command.example.editor.Editor; public class CutCommand extends Command { public CutCommand(Editor editor) { super(editor); } @Override public boolean execute() { if (editor.textField.getSelectedText().isEmpty()) return false; backup(); String source = editor.textField.getText(); editor.clipboard = editor.textField.getSelectedText(); editor.textField.setText(cutString(source)); return true; } private String cutString(String source) { String start = source.substring(0, editor.textField.getSelectionStart()); String end = source.substring(editor.textField.getSelectionEnd()); return start + end; } } 

commands/CommandHistory.java: История команд

package refactoring_guru.command.example.commands; import java.util.Stack; public class CommandHistory { private Stack<Command> history = new Stack<>(); public void push(Command c) { history.push(c); } public Command pop() { return history.pop(); } public boolean isEmpty() { return history.isEmpty(); } } 

editor

editor/Editor.java: Оболочка текстового редактора

package refactoring_guru.command.example.editor; import refactoring_guru.command.example.commands.*; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class Editor { public JTextArea textField; public String clipboard; private CommandHistory history = new CommandHistory(); public void init() { JFrame frame = new JFrame("Text editor (type & use buttons, Luke!)"); JPanel content = new JPanel(); frame.setContentPane(content); frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS)); textField = new JTextArea(); textField.setLineWrap(true); content.add(textField); JPanel buttons = new JPanel(new FlowLayout(FlowLayout.CENTER)); JButton ctrlC = new JButton("Ctrl+C"); JButton ctrlX = new JButton("Ctrl+X"); JButton ctrlV = new JButton("Ctrl+V"); JButton ctrlZ = new JButton("Ctrl+Z"); Editor editor = this; ctrlC.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { executeCommand(new CopyCommand(editor)); } }); ctrlX.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { executeCommand(new CutCommand(editor)); } }); ctrlV.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { executeCommand(new PasteCommand(editor)); } }); ctrlZ.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { undo(); } }); buttons.add(ctrlC); buttons.add(ctrlX); buttons.add(ctrlV); buttons.add(ctrlZ); content.add(buttons); frame.setSize(450, 200); frame.setLocationRelativeTo(null); frame.setVisible(true); } private void executeCommand(Command command) { if (command.execute()) { history.push(command); } } private void undo() { if (history.isEmpty()) return; Command command = history.pop(); if (command != null) { command.undo(); } } } 

Demo.java: Клиентский код

package refactoring_guru.command.example; import refactoring_guru.command.example.editor.Editor; public class Demo { public static void main(String[] args) { Editor editor = new Editor(); editor.init(); } } 

OutputDemo.png: Результат выполнения

Команда на других языках программирования

Команда на C# Команда на C++ Команда на Go Команда на PHP Команда на Python Команда на Ruby Команда на Rust Команда на Swift Команда на TypeScript