命令模式(Command),将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销操作。
下面给出命令模式的结构图:
下面是命令模式的基本结构代码:
namespace ConsoleApplication1 { abstract class Command { protected Receiver receiver; public Command(Receiver receiver) { this.receiver = receiver; } abstract public void Execute(); } //ConcreteCommand类,将一个接收者对象绑定于一个动作,调用接收者相应的操作,以实现Execute class ConcreteCommand : Command { public ConcreteCommand(Receiver receiver) : base(receiver) { } public override void Execute() { receiver.Action(); } } //Invoker类,要求该命令执行这个请求 class Invoker { private Command command; public void SetCommand(Command command) { this.command = command; } public void ExecuteCommand() { command.Execute(); } } //Receiver类,知道如何实施与执行一个请求相关的操作,任何类都可能作为一个接收者 class Receiver { public void Action() { Console.WriteLine("执行请求!"); } } class Program { static void Main(string[] args) { Receiver r = new Receiver(); Command c = new ConcreteCommand(r); Invoker i = new Invoker(); i.SetCommand(c); i.ExecuteCommand(); Console.ReadKey(); } } }
命令模式的优点:
1、它能较容易地设计一个命令队列;
2、在需要的情况下,可以叫容易地将命令计入日志;
3、允许接收请求的一方决定是否要否决请求。
4、可以容易地实现对请求的撤销和重做;
5、由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易。
6、最关键的一点,命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分割开。
回到《大话设计模式》书中的烧烤例子:
namespace ConsoleApplication1 { public class Barbecuer { //烤羊肉 public void BakeMutton() { Console.WriteLine("烤羊肉串"); } //烤鸡翅 public void BakeChickenWing() { Console.WriteLine("烤鸡翅"); } } //抽象命令 public abstract class Command { protected Barbecuer receiver; public Command(Barbecuer receiver) //抽象命令类,只需要确定‘烤羊肉串者’是谁 { this.receiver = receiver; } //执行命令 abstract public void ExecuteCommand(); } //烤羊肉串命令 class BakeMuttonCommand : Command { public BakeMuttonCommand(Barbecuer receiver) : base(receiver) { } public override void ExecuteCommand() { receiver.BakeMutton(); } } //烤鸡翅命令 class BakeChickenWingCommand : Command { public BakeChickenWingCommand(Barbecuer receiver) : base(receiver) { } public override void ExecuteCommand() { receiver.BakeChickenWing(); } } //服务员类 public class Waiter { private IList<Command> orders = new List<Command>(); //增加存放具体命令的容器 //设置订单 public void SetOrder(Command command) //在客户提出请求时,对没货的烧烤进行回绝 { if (command.ToString() == "命令模式.BakeChickenWingCommand") { Console.WriteLine("服务员:鸡翅没有了,请点别的烧烤"); } else { orders.Add(command); Console.WriteLine("增加订单:" + command.ToString() + " 时间:" + DateTime.Now.ToString()); } } //取消订单 public void CancelOrder(Command command) //记录客户所点的烧烤的日志,以便算账收钱 { orders.Remove(command); Console.WriteLine("取消订单:" + command.ToString() + " 时间:" + DateTime.Now.ToString()); } //通知全部执行 public void Notify() { foreach (Command cmd in orders) { cmd.ExecuteCommand(); } } } class Program { static void Main(string[] args) { //开店前的准备 Barbecuer boy = new Barbecuer(); Command bakeMuttonCommand1 = new BakeMuttonCommand(boy); Command bakeMuttonCommand2 = new BakeMuttonCommand(boy); Command bakeChickenWingCommand1 = new BakeChickenWingCommand(boy); Waiter girl = new Waiter(); //开门营业 girl.SetOrder(bakeMuttonCommand1); girl.SetOrder(bakeMuttonCommand2); girl.SetOrder(bakeChickenWingCommand1); //点菜完毕,通知厨房 girl.Notify(); //订单下好后,一次性通知 在通知之前都可以取消 Console.ReadKey(); } } }