一、引言:
路邊有一個烤肉攤,有一位老板負責給客人燒烤食物。如果客人很少,老板都能準確記住大家的要求,隨著客人的增多,要求越來越多,老板很難滿足大家要求,老板應該怎么辦?
首先說明為什么客人多了,老板滿足不了大家的要求,因為“用程序猿的話說是因為:緊耦合”。松耦合就能很好的解決此問題,也就是本文介紹的命令模式。先給出緊耦合代碼:

class PRogram { static void Main(string[] args) { Receiver receiver = new Receiver(); receiver.BakeChickenWing(); Console.Read(); } } public class Receiver//boss { public void BakeMutton() { Console.WriteLine("bake mutton"); } public void BakeChickenWing() { Console.WriteLine("bake chickenwing"); } }
二、定義:
命令模式:將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日志,以及支持可撤銷操作。
解釋:將請求命令封裝為一個對象,并用日志記錄下來,其中它支持命令撤銷功能。
三、UML圖及基本代碼:

基本代碼:
class Receicer { public void Action() { Console.WriteLine("執行請求"); } } abstract class Command { protected Receicer receiver; public Command(Receicer receiver) { this.receiver = receiver; } abstract public void Execute(); } class ConcreteCommand : Command { public ConcreteCommand(Receicer receiver) : base(receiver) { } public override void Execute() { receiver.Action(); } } class Invoker { private Command command; public void SetCommand(Command command) { this.command = command; } public void ExecuteCommand() { command.Execute(); } }
調用:
Receicer receiver = new Receicer(); Command command = new ConcreteCommand(receiver); Invoker invoker = new Invoker();
invoker.SetCommand(command);
invoker.ExecuteCommand();
解釋:映射客人到酒店就餐。Receiver是命令的接收者,相當于酒店中的大廚;Command命令抽象類,ConcreteCommand是具體的命令,相當于點菜請求,命令中應該包含命令的接收者。Invoke是命令的傳達者,相當于酒店的服務員,負責記錄客人點菜請求,并傳達給后廚。
四、舉例說明:
學校高一學生進行軍訓,校長發布讓學生跑10000米的命令。整個過程:校長發布命令給軍訓教官,教官傳達校長命令給學生,學生接收到命令后執行相應的操作。在下面實例中,Receiver是學生,操作跑10000米的命令。Command是命令,必需知道命令的接收者。Drillmaster是教官,教官必需知道命令是什么,并傳達命令。

//校長發布學生跑1000米的命令,教官傳達此命令給學生,學生是命令的接收者 //客戶端:校長,命令的發出者必須知道具體的命令、接受者、傳達命令者 class Program { static void Main(string[] args) { Receiver receiver = new Receiver(); Command command = new ConcreteCommand(receiver); Drillmaster drillmaster = new Drillmaster(command); drillmaster.ExecuteCommand(); Console.Read(); } } //命令接收者 public class Receiver { public void Run1000Meters() { Console.WriteLine("跑10000米"); } } //抽象命令 public abstract class Command { protected Receiver receiver; public Command(Receiver receiver) { this.receiver = receiver; } public abstract void Action(); } //具體的命令,必須知道命令接受者 public class ConcreteCommand : Command { public ConcreteCommand(Receiver receiver) : base(receiver) { } public override void Action() { receiver.Run1000Meters(); } } //教官:命令的傳達者,負責調用命令對象的方法來保證命令執行 public class Drillmaster { public Command command; public Drillmaster(Command command) { this.command = command; } public void ExecuteCommand() { command.Action(); } }
五、解決引言中的問題
客人點菜命令的接收者,老板(大廚):
public class Receiver { public void BakeMutton() { Console.WriteLine("bake mutton"); } public void BakeChickenWing() { Console.WriteLine("bake chickenwing"); } }
點菜命令:
public abstract class Command { protected Receiver receiver; public Command(Receiver receiver) { this.receiver = receiver; } abstract public void Execute(); } class ConcreteCommand1 : Command { public ConcreteCommand1(Receiver receiver) : base(receiver) { } public override void Execute() { receiver.BakeMutton(); } } class ConcreteCommand2 : Command { public ConcreteCommand2(Receiver receiver) : base(receiver) { } public override void Execute() { receiver.BakeChickenWing(); } }
增加一個服務生,負責記錄客人點菜命令,并傳達給大廚。點菜命令可以進行增加或取消操作。
public class Invoker { private IList<Command> commands = new List<Command>(); public void AddCommand(Command command) { commands.Add(command); Console.WriteLine("增加訂單" + command.ToString()); } public void CancelCommand(Command command) { commands.Remove(command); Console.WriteLine("取消訂單" + command.ToString()); } public void ExecuteCommand() { foreach (Command command in commands) { command.Execute(); } } }
客戶端調用:
Receiver receiver = new Receiver(); Command command1 = new ConcreteCommand1(receiver); Command command2 = new ConcreteCommand2(receiver); Invoker invoker = new Invoker(); invoker.AddCommand(command1); invoker.AddCommand(command2); invoker.CancelCommand(command1); invoker.ExecuteCommand();
六、優缺點及適用場景
優點:
比較容易的設計一個命令隊列;在需要的情況下,可以比較容易的將命令計入日志;允許接收請求的一方決定是否要否決請求;比較容易的對命令實現撤銷和重做;由于加入新的具體命令類不影響其他的類,因此增加新的具體命令類比較容易。
缺點:
可能會導致系統具有過多的具體命令類。
適用場景:
個人理解:基本上能表現其優點的地方都可以使用命令模式。
新聞熱點
疑難解答