定義
? ? ? ? Command Partern: 將一個請求封裝成一個對象,從而讓你使用不同的請求把客戶端參數化,對請求排隊或者記錄請求日志,可以提供命令的撤銷和恢復功能。(核心思想是將“動作”與“執行者”解耦)
場景
-
GUI:操作將UI控件與業務邏輯解耦,一個命令可被多處復用。
-
撤銷/重做:通過記錄命令歷史和狀態,實現操作的回逆。
-
任務隊列:實現任務的延遲執行和異步處理,解耦生產與消費。
-
宏錄制:使用組合模式將多個命令組合成一個宏命令。
-
事務系統:提供原子操作和回滾機制。
-
異步回調:封裝未來需要執行的操作,實現模塊間的解耦通信。
Java中的典型場景
-
Swing/AWT事件處理:
ActionListener
本質是命令模式。 -
線程池:
Runnable
或Callable
任務封裝了執行邏輯。 -
事務管理:數據庫操作封裝為可回滾的命令對象。
代碼
import java.util.Stack;
// 文檔編輯器的撤銷和執行
// 命令接口
interface EditorCommand {void execute();void undo();
}// 接收者:文檔
class Document {private StringBuilder content = new StringBuilder();public String getContent() {return content.toString();}public void insertText(String text) {content.append(text);System.out.println("插入文本: " + text + ",當前內容: " + content);}public void deleteText(int length) {if (length > content.length()) {length = content.length();}String deleted = content.substring(content.length() - length);content.delete(content.length() - length, content.length());System.out.println("刪除文本: " + deleted + ",當前內容: " + content);}
}// 具體命令:插入文本
class InsertCommand implements EditorCommand {private Document document;private String text;public InsertCommand(Document doc, String text) {this.document = doc;this.text = text;}@Overridepublic void execute() {document.insertText(text);}@Overridepublic void undo() {document.deleteText(text.length());}
}// 調用者:編輯器
class TextEditor {private Stack<EditorCommand> commandHistory = new Stack<>();private Stack<EditorCommand> redoStack = new Stack<>();public void executeCommand(EditorCommand command) {command.execute();commandHistory.push(command);redoStack.clear(); // 執行新命令后清空重做棧}public void undo() {if (!commandHistory.isEmpty()) {EditorCommand command = commandHistory.pop();command.undo();redoStack.push(command);System.out.println("執行撤銷操作");} else {System.out.println("沒有可撤銷的操作");}}public void redo() {if (!redoStack.isEmpty()) {EditorCommand command = redoStack.pop();command.execute();commandHistory.push(command);System.out.println("執行重做操作");} else {System.out.println("沒有可重做的操作");}}
}// 測試類class TextEditorDemo {public static void main(String[] args) {Document doc = new Document();TextEditor editor = new TextEditor();System.out.println("=== 編輯文檔過程 ===");editor.executeCommand(new InsertCommand(doc, "Hello "));editor.executeCommand(new InsertCommand(doc, "World "));editor.executeCommand(new InsertCommand(doc, "Java!"));System.out.println("\n=== 撤銷操作 ===");editor.undo(); // 撤銷插入"Java!"editor.undo(); // 撤銷插入"World "System.out.println("\n=== 重做操作 ===");editor.redo(); // 重做插入"World "editor.redo(); // 重做插入"Java!"}
}
生活中的示例:文檔編輯器撤銷 (Undo) 和重做 (Redo) 功能,比如餐廳點餐系統的例子:服務員(調用者)接收顧客的點單(命令),然后交給廚房(接收者)執行。在比如家電遙控器:遙控器上的每個按鈕都對應一個命令,按下按鈕就執行相應操作(開、關、調節等)
命令模式代碼