設計模式(六)——命令模式
命令模式:將“請求”封裝成對象,以便使用不同的請求,隊列或者日誌來參數化其他對象,命令模式也支持可撤銷的操作。
一個命令對象通過在特定的接收者上面綁定一組動作來封裝這個請求。要達到這一點,命令對象將接收者和動作封裝在一個對象中,只暴露出一個Execute()方法。當此方法調用則進行接收者的動作。從外面看來,其他對象不需要知道哪個接收者進行了哪些動作,只知道如果調用了Execute()方法,請求的目的就能達到。
例如有一個簡單的遙控器能夠控制燈的開關:
首先定義Command接口:
1 interface ICommand 2 3 { 4 5 voidView CodeExecute(); 6 7 }
隨後創建接收者:
1 public class Light 2 3 { 4 5 public void LightOn() 6 7 { 8 9 Console.WriteLine("燈亮"); 10 11 } 12 13 public void LightOff() 14 15 { 16 17 Console.WriteLine("View Code燈滅"); 18 19 } 20 21 }
創建命令對象:
1 public class LightOnCommand : ICommand 2 3 { 4 5 public Light light; 6 7 public LightCommand(Light light) 8 9 { 10 11 this.light = light; 12 13 } 14 15 public void Execute()View Code16 17 { 18 19 light.LightOn(); 20 21 } 22 23 }
實現遙控器:
1 public class RemoteCtrl 2 3 { 4 5 ICommand command = new LightCommand(new Light()); 6 7 public void Click() 8 9 { 10 11 command.Execute(); 12 13 } 14 15 }View Code
若有多個命令對象可以創建命令對象數組,並創建一個NoComand對象作為初始化使用,這樣避免無命令的時候的錯誤。
當有多個命令的時候,可能會遇見撤銷的操作,這時候可以在命令對象中增加UnDo操作,表示撤回例如:
1 public class LightOnCommand : ICommand 2 3 { 4 public Light light; 5 6 public LightCommand(Light light) 7 8 { 9 10 this.light = light; 11 12 } 13 14 public void Execute() 15 16 { 17 18 light.LightOn(); 19 20 } 21 22 Public void UnDo(){ 23 24 Light.LightOff(); 25 26 } 27 28 }View Code
可以在操作者對象設置一個Command命令,存儲撤回的Command。即執行UnDo操作。
使用宏命令(Party模式),能夠一次性執行多個命令。創建新的Command,將其他Command放入這裏,在一個Execute中,執行所有的Command。
如果有多級需要撤銷的可以考慮采用隊列。
一些常見問題:
接收者是否一定要存在?
一般來說,我們盡量設計“傻瓜模式”,它只懂得調用一個接收者的行為。然而也可以設計成“聰明模式”,在Execute執行邏輯細節,但是這樣調用者和接收者的解耦程度是比不上“傻瓜模式”的,而且也不能將接收者當作對象傳遞。
宏命令可以在Execute中執行所需對象的命令,而不采用其他命令對象嗎?
這種方法也可以,不過相當於進行了“硬編碼”到了命令對象中。而利用宏命令可以動態改變命令對象,顯然宏命令更加優雅,也需要較少的新代碼。
設計模式(六)——命令模式