
Polecenie w języku Java
Polecenie to behawioralny wzorzec projektowy według którego żądania lub proste działania są konwertowane na obiekty.
Wyżej wymieniona konwersja pozwala odkładać zadania w czasie, uruchamiać je zdalnie, przechowywać ich historię, itp.
Złożoność:
Popularność:
Przykłady użycia: Wzorzec Polecenie jest dość powszechny w kodzie napisanym w Javie jako alternatywa dla wywołania zwrotnego (ang. callback) zakładającego przypisanie akcji elementom interfejsu użytkownika w odpowiedzi na różne interakcje z tymi elementami. Jest stosowany także w celu kolejkowania zadań, śledzenia historii wykonanych działań, itp.
Oto parę przykładów użycia wzorca Polecenie w głównych bibliotekach Java:
-
Wszystkie implementacje
java.lang.Runnable
-
Wszystkie implementacje
javax.swing.Action
Identyfikacja: Jeśli widzisz zestaw powiązanych klas odpowiadających konkretnym czynnościom (jak “Kopiuj”, “Wytnij”, “Wyślij”, “Drukuj”, itd.) — może to oznaczać użycie wzorca Polecenie. Takie klasy powinny implementować ten sam interfejs/klasę abstrakcyjną. Polecenia mogą samodzielnie implementować poszczególne czynności lub delegować zadania osobnym obiektom — zwanym odbiorcami. Ostatnim elementem układanki jest znalezienie obiektu wywołującego — będzie to klasa przyjmująca obiekty-polecenia w charakterze parametrów swoich metod lub konstruktora.
Polecenia edytora tekstu oraz funkcjonalność ‘cofnij’
Edytor tekstu w poniższym przykładzie tworzy nowe obiekty-polecenia przy okazji każdej interakcji użytkownika z programem. Po wykonaniu swoich zadań, polecenie trafia na stos stanowiący historię poleceń.
Aby cofnąć czynność, aplikacja pobiera ostatnio uruchomione polecenie z historii i albo wykonuje odwrotną czynność, albo przywraca wcześniejszy stan edytora, zapisany przez to polecenie.
commands
commands/Command.java: Abstrakcyjne bazowe polecenie
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: Kopiuj zaznaczony tekst do schowka
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: Wklej tekst ze schowka
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: Wytnij tekst i umieść w schowku
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: Historia poleceń
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: GUI edytora tekstu
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: Kod klienta
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: Wynik działania
