
자바로 작성된 커맨드
커맨드는 요청 또는 간단한 작업을 객체로 변환하는 행동 디자인 패턴입니다.
이러한 변환은 명령의 지연 또는 원격 실행, 명령 기록 저장 등을 허용합니다.
복잡도:
인기도:
사용 예시들: 커맨드 패턴은 자바 코드에서 매우 일반적입니다. 대부분의 경우 작업으로 UI 요소를 매개 변수화하기 위한 콜백의 대안으로 사용되며 작업 대기, 작업 기록 추적 등에도 사용됩니다.
다음은 코어 자바 라이브러리로부터 가져온 몇 가지 예시들입니다:
-
java.lang.Runnable
의 모든 구현 -
javax.swing.Action
의 모든 구현
식별: 특정 작업(예: '복사', '잘라내기', '보내기', '인쇄' 등)을 나타내는 관련 클래스들의 집합이 존재하는 경우 이는 커맨드 패턴일 수 있습니다. 이러한 클래스들은 같은 인터페이스/추상 클래스를 구현해야 합니다. 커맨드는 자체적으로 관련 작업을 구현하거나 작업을 별도의 객체(수신자가 될 객체)에 위임할 수 있습니다. 퍼즐의 마지막 조각은 호출자를 식별하는 것입니다. 자신의 메서드들 또는 생성자들의 매개변수들에서부터 커맨드 객체들을 받는 클래스를 검색하세요.
텍스트 편집기 커맨드들 및 실행 취소
이 예시의 텍스트 편집기는 사용자가 상호 작용할 때마다 새 커맨드 객체를 만듭니다. 작업을 실행한 후 명령이 기록 스택으로 푸시됩니다.
이제 실행 취소 작업을 수행하기 위해 응용 앱은 기록에서 마지막으로 실행된 명령을 가져와 역동작을 수행하거나 해당 명령에 따라 저장된 편집기의 과거 상태를 복원합니다.
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: 실행 결과
