烤羊肉串引来的思考 命令模式
23.1 吃烤羊肉串
23.2 烧烤摊VS烧烤店
行为请求者与行为实现者的紧耦合,
23.3 紧耦合设计
namespace 命令模式 { class Program { static void Main(string[] args) { Barbecuer boy = new Barbecuer(); boy.BakeMutton(); boy.BakeMutton(); boy.BakeMutton(); boy.BakeChickenWing(); boy.BakeMutton(); boy.BakeMutton(); boy.BakeChickenWing(); Console.Read(); } } //烤肉串者 public class Barbecuer { //烤羊肉 public void BakeMutton() { Console.WriteLine("烤羊肉串!"); } //烤鸡翅 public void BakeChickenWing() { Console.WriteLine("烤鸡翅!"); } } }
23.4 松耦合设计
namespace 命令模式 { 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.Notify(); girl.SetOrder(bakeMuttonCommand2); girl.Notify(); girl.SetOrder(bakeChickenWingCommand1); girl.Notify(); Console.Read(); } } //烤肉串者, 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 ExcuteCommand(); } //烤羊肉串命令, class BakeMuttonCommand : Command { public BakeMuttonCommand(Barbecuer receiver) : base(receiver) { } public override void ExcuteCommand() //执行命令时,执行具体的行为, { receiver.BakeMutton(); } } //烤鸡翅命令, class BakeChickenWingCommand : Command { public BakeChickenWingCommand(Barbecuer receiver) : base(receiver) { } public override void ExcuteCommand() { receiver.BakeChickenWing(); } } //服务员, public class Waiter { private Command command; //设置订单, public void SetOrder(Command command) //不用管用户想要什么烤肉,反正都是命令,只管记录订单,通知烤肉串者即可, { this.command = command; } //通知执行, public void Notify() { command.ExcuteCommand(); } } }
23.5 松耦合后
namespace 命令模式 { 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.Read(); } } //烤肉串者, 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 ExcuteCommand(); } //烤羊肉串命令, class BakeMuttonCommand : Command { public BakeMuttonCommand(Barbecuer receiver) : base(receiver) { } public override void ExcuteCommand() { receiver.BakeMutton(); } } //烤鸡翅命令, class BakeChickenWingCommand : Command { public BakeChickenWingCommand(Barbecuer receiver) : base(receiver) { } public override void ExcuteCommand() { 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.ExcuteCommand(); } } } }
23.6 命令模式
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作,
namespace 命令模式 { class Program { static void Main(string[] args) { Receiver r = new Receiver(); Command c = new ConcreteCommand(r); Invoker i = new Invoker(); // Set and execute command i.SetCommand(c); i.ExecuteCommand(); Console.Read(); } } //用来声明执行操作的接口, abstract class Command { protected Receiver receiver; public Command(Receiver receiver) { this.receiver = receiver; } abstract public void Execute(); } //将一个接收者对象绑定于一个动作,调用接收者相应的操作,以实现Execute方法, class ConcreteCommand : Command { public ConcreteCommand(Receiver 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(); } } //知道如何实施与执行一个与请求相关的操作,任何类都可能作为一个接收者, class Receiver { public void Action() { Console.WriteLine("执行请求!"); } } }
23.7 命令模式作用
命令模式优点,第一,它能较容易的设计一个命令队列,第二,在需要的情况下,可以较容易的将命令记入日志,第三,允许接收请求的一方决定是否要否决请求,第四,可以容易的实现对请求的撤销和重做,第五,由于加进新的具体命令类不影响其它的类,因此增加新的具体命令类很容易,最关键的优点就是命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分割开,
敏捷开发原则告诉我们,不要为代码添加基于猜测的,实际不需要的功能,如果不清楚一个系统是否需要命令模式,一般就不要着急去实现它,事实上,在需要的时候通过重构实现这个模式并不困难,只有在真正需要如撤销/恢复操作等功能时,把原来的代码重构为命令模式才有意义,