命令模式(Command Pattern)
命令模式(Command Pattern)是一種行為型設計模式,它將請求(命令)封裝成對象,從而使您能夠參數化客戶端(調用者)使用不同的請求、隊列請求或者日志請求,甚至支持可撤銷的操作。
核心思想是?將請求封裝成對象,從而使得調用者與接收者解耦,同時支持請求的存儲、撤銷、重做和排隊執行。
主要組成部分
-
Command(命令接口):通常是一個接口,定義一個執行命令的?
execute()
?方法。 -
ConcreteCommand(具體命令):實現命令接口,并定義執行該命令的具體操作,通常將請求的接收者(Receiver)和操作綁定在一起。
-
Client(客戶端):創建一個具體命令對象并設置其接收者(Receiver)。
-
Invoker(調用者):請求命令的執行。通常在用戶操作時,會調用?
execute()
?方法。 -
Receiver(接收者):知道如何實施與執行一個請求相關的操作,實際的業務邏輯通常由此類執行。
案例實現
一個?圖形編輯器,用戶可以執行對圖形的操作(如繪制、擦除等),并能夠撤銷這些操作。
案例類圖
命令調用者類
依賴于命令接口,命令接口下的具體命令類
操作實際的業務邏輯
。
Command接口
public interface Command {void execute();void undo();
}
繪制圖形命令
// ConcreteCommand - 繪制圖形命令
public class DrawShapeCommand implements Command {private Shape shape;public DrawShapeCommand(Shape shape) {this.shape = shape;}@Overridepublic void execute() {shape.draw();}@Overridepublic void undo() {shape.erase();}
}// ConcreteCommand - 刪除圖形命令
class EraseShapeCommand implements Command {private Shape shape;public EraseShapeCommand(Shape shape) {this.shape = shape;}@Overridepublic void execute() {shape.erase();}@Overridepublic void undo() {shape.draw();}
}
接受者--抽象圖形類
public abstract class Shape {protected String name;public abstract void draw();public abstract void erase();
}
接受者--具體圖形類
public class Circle extends Shape {public Circle() {this.name = "Circle";}@Overridepublic void draw() {System.out.println("繪制圖形 " + name);}@Overridepublic void erase() {System.out.println("擦除圖形 " + name);}
}class Rectangle extends Shape {public Rectangle() {this.name = "Rectangle";}@Overridepublic void draw() {System.out.println("繪制圖形 " + name);}@Overridepublic void erase() {System.out.println("擦除圖形 " + name);}
}
命令調用者
public class CommandInvoker {private Stack<Command> commandHistory = new Stack<>();public void executeCommand(Command command) {command.execute();commandHistory.push(command);}public void undo() {if (!commandHistory.isEmpty()) {Command lastCommand = commandHistory.pop();lastCommand.undo();} else {System.out.println("No commands to undo.");}}
}
測試代碼
public class CommandDemo {public static void main(String[] args) {// 創建圖形Shape circle = new Circle();Shape rectangle = new Rectangle();// 創建命令Command drawCircleCommand = new DrawShapeCommand(circle);Command drawRectangleCommand = new DrawShapeCommand(rectangle);Command eraseCircleCommand = new EraseShapeCommand(circle);Command eraseRectangleCommand = new EraseShapeCommand(rectangle);// 創建命令調用者CommandInvoker invoker = new CommandInvoker();// 執行命令invoker.executeCommand(drawCircleCommand); // 繪制圓形invoker.executeCommand(drawRectangleCommand); // 繪制矩形invoker.executeCommand(eraseCircleCommand); // 刪除圓形invoker.executeCommand(eraseRectangleCommand); // 刪除矩形// 撤銷操作invoker.undo(); // 撤銷刪除矩形invoker.undo(); // 撤銷刪除圓形invoker.undo(); // 撤銷繪制矩形invoker.undo(); // 撤銷繪制圓形invoker.undo();}
}
測試結果
繪制圖形 Circle
繪制圖形 Rectangle
擦除圖形 Circle
擦除圖形 Rectangle
繪制圖形 Rectangle
繪制圖形 Circle
擦除圖形 Rectangle
擦除圖形 Circle
No commands to undo.
優缺點和適用場景
優點:
-
解耦請求者和接收者:請求者(客戶端)不需要知道接收者的具體實現,只需要知道命令接口。
-
支持撤銷操作:可以將命令對象設計為支持撤銷的操作,使得某些操作能夠撤回。
-
可以將命令參數化:命令可以作為參數傳遞,或被存儲起來,支持批量操作。
-
擴展性好:增加新的命令時,不需要改變現有代碼,只需要新增具體命令類。
缺點:
-
增加類的數量:每個具體命令類都需要創建一個類,可能導致類的數量增多。
-
實現復雜度:如果系統中的命令非常多,可能導致命令類實現過于復雜。
命令模式在 GUI 程序、事務管理、隊列任務等場景中非常常見。
適用場景
-
需要解耦請求者和接收者。
-
需要撤銷、重做操作。
-
需要存儲請求、支持隊列、日志功能。
-
需要動態選擇操作或擴展操作。
-
需要將多個操作封裝為一個命令。
-
需要管理跨平臺或多設備的操作。
總結
命令模式的核心關注點是將請求封裝成對象,從而使得請求的發送者(調用者)和接收者(執行者)解耦。命令模式通過把請求封裝成命令對象,使得你可以在不改變請求者的情況下改變請求的執行方式、順序或者操作對象。
-
行為封裝:命令模式將請求、操作或事務封裝為命令對象,這些對象可以被請求者調用。請求者不關心具體操作的執行方式,只需要調用命令對象的執行方法即可。
-
請求者和執行者解耦:通過引入命令對象,調用者和被調用者的關系被解耦,調用者不需要知道如何執行操作,也不需要知道具體的操作是什么,只需要發出命令請求。
文章轉載自:淵渟岳
原文鏈接:掌握設計模式--命令模式 - 淵渟岳 - 博客園
體驗地址:JNPF快速開發平臺