命令模式(22)
今天我们来讲一下命令模式。
一、案例
我们去烧烤店吃烧烤,给我们烤羊肉串和鸡翅。用简单的控制台应用程序来模拟一下。
1 /// <summary> 2 /// 烤肉串者 3 /// </summary> 4 public class Barbecurer 5 { 6 public void BakeMutton() 7 { 8 Console.WriteLine("烤羊肉串!"); 9 } 10 11 public void BakeChickenWing() 12 { 13 Console.WriteLine("烤鸡翅!"); 14 } 15 }
客户端调用:
1 public static void Main() 2 { 3 Barbecurer boy = new Barbecurer(); 4 boy.BakeMutton(); 5 boy.BakeMutton(); 6 boy.BakeMutton(); 7 boy.BakeChickenWing(); 8 boy.BakeMutton(); 9 boy.BakeMutton(); 10 Console.ReadKey(); 11 }
二、演绎
1、第一步演绎
如果烧烤店里有好多人,都要了若干的烤串和鸡翅,那么,烤肉串者怎么记得谁点了什么,点了多少串呢?这样就会乱掉了。如何解决这个问题呢?我们需要服务员,需要菜单,这样就可以分清了。好,我们来修改一下我们的代码。
1 /// <summary> 2 /// 烤肉串者 3 /// </summary> 4 public class Barbecurer 5 { 6 public void BakeMutton() 7 { 8 Console.WriteLine("烤羊肉串!"); 9 } 10 11 public void BakeChickenWing() 12 { 13 Console.WriteLine("烤鸡翅!"); 14 } 15 } 16 //抽象命令类 17 public abstract class Command 18 { 19 protected Barbecurer receiver; 20 21 public Command(Barbecurer receiver) 22 { 23 this.receiver = receiver; 24 } 25 26 abstract public void ExcuteCommand(); 27 } 28 //烤鸡翅命令 29 class BakeChickenWingCommand : Command 30 { 31 public BakeChickenWingCommand(Barbecurer receiver) : base(receiver) 32 { 33 } 34 public override void ExcuteCommand() 35 { 36 receiver.BakeChickenWing(); 37 } 38 } 39 //服务员 40 public class Waiter 41 { 42 private Command command; 43 //服务员类,不用管用户想要什么烤肉,反正都是‘命令’,只管记录订单,然后通知‘烤肉串者’执行即可 44 public void SetOrder(Command command) 45 { 46 this.command = command; 47 } 48 49 public void Notify() 50 { 51 command.ExcuteCommand(); 52 } 53 }
客户端调用:
1 public static void Main() 2 { 3 //开店前准备 4 //烧烤店准备好烤肉厨师,服务员,菜单,就等客户上门 5 Barbecurer boy = new Barbecurer(); 6 Command bakeMuttonCommand1 = new BakeMuttonCommand(boy); 7 Command bakeMuttonCommand2 = new BakeMuttonCommand(boy); 8 Command bakeChickenWingCommand1 = new BakeChickenWingCommand(boy); 9 Waiter girl = new Waiter(); 10 11 //开门营业 12 //服务员根据用户要求,通知厨房开始制作 13 girl.SetOrder(bakeMuttonCommand1); 14 girl.Notify(); 15 girl.SetOrder(bakeMuttonCommand2); 16 girl.Notify(); 17 girl.SetOrder(bakeChickenWingCommand1); 18 girl.Notify(); 19 Console.ReadKey(); 20 }
2、第二步演绎
在这里,我们还有几个问题
①真实情况并不是客户点一个菜服务员就去通知厨房做一个菜,而是客户点完之后,服务员再报给厨房制作。
②如果某样菜没了,客户是不知道的,应该由服务员或者厨师来判断这个菜是否还有。
③客户点了很多东西,是需要记录下来的,以便后面结账使用。
④如果客户点完菜了,觉得点多了,需要取消几样菜。
好,针对上述问题,我们再来修改一下代码:
我们需要修改一下服务员类
1 //服务员 2 public class Waiter 3 { 4 //增加存放具体命令的容器 5 private IList<Command> orders = new List<Command>(); 6 //设置订单 7 public void SetOrder(Command command) 8 { 9 if (command.ToString() == "MyTest.BakeChickenWingCommand") 10 { 11 Console.WriteLine("鸡翅没有了,请点别的烧烤"); 12 } 13 else 14 { 15 orders.Add(command); 16 Console.WriteLine($"增加订单:{command.ToString()},时间:{DateTime.Now}"); 17 } 18 } 19 //取消订单 20 public void CancelOrder(Command command) 21 { 22 orders.Remove(command); 23 Console.WriteLine($"取消订单:{command.ToString()},时间:{DateTime.Now}"); 24 } 25 //通知全部执行 26 public void Notity() 27 { 28 //根据用户点好的订单通知厨房制作 29 foreach (Command cmd in orders) 30 { 31 cmd.ExcuteCommand(); 32 } 33 } 34 }
客户端调用:
1 public static void Main() 2 { 3 //开店前准备 4 //烧烤店准备好烤肉厨师,服务员,菜单,就等客户上门 5 Barbecurer boy = new Barbecurer(); 6 Command bakeMuttonCommand1 = new BakeMuttonCommand(boy); 7 Command bakeMuttonCommand2 = new BakeMuttonCommand(boy); 8 Command bakeChickenWingCommand1 = new BakeChickenWingCommand(boy); 9 Waiter girl = new Waiter(); 10 11 //开门营业 12 //服务员根据用户要求,通知厨房开始制作 13 girl.SetOrder(bakeMuttonCommand1); 14 girl.SetOrder(bakeMuttonCommand2); 15 girl.SetOrder(bakeChickenWingCommand1); 16 17 //点完菜,通知厨房 18 girl.Notity(); 19 Console.ReadKey(); 20 }
这样,我们的问题都解决了,以上呢,其实就是用到了命令模式。
好,下面我们来总结一下命令模式:
命令模式:讲一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化对请求排队或记录请求日志,以及支持可撤销的操作。
来看一下命令模式的基本代码:
1 /// <summary> 2 /// 声明执行操作的接口 3 /// </summary> 4 abstract class Command 5 { 6 protected Receiver receiver; 7 8 public Command(Receiver receiver) 9 { 10 this.receiver = receiver; 11 } 12 13 abstract public void Execute(); 14 } 15 /// <summary> 16 /// 具体的命令操作 17 /// </summary> 18 class ConcreteCommand:Command 19 { 20 //将一个接收者对象绑定于这个动作,调用接受者相应的操作,以实现Execute 21 public ConcreteCommand(Receiver receiver) : base(receiver) 22 { 23 } 24 25 public override void Execute() 26 { 27 receiver.Action(); 28 } 29 } 30 //命令的接受者 31 class Receiver 32 { 33 public void Action() 34 { 35 Console.WriteLine("执行请求!"); 36 } 37 } 38 //要求该命令执行这个请求 39 class Invoker 40 { 41 private Command command; 42 43 public void SetCommand(Command command) 44 { 45 this.command = command; 46 } 47 48 public void ExecuteCommand() 49 { 50 command.Execute(); 51 } 52 }
客户端调用:
1 public static void Main() 2 { 3 Receiver r = new Receiver(); 4 Command c = new ConcreteCommand(r); 5 Invoker i = new Invoker(); 6 i.SetCommand(c); 7 i.ExecuteCommand(); 8 Console.ReadKey(); 9 }
以上就是命令模式的基本代码。
好了,命令模式今天就讲到这里,下一篇我们讲 职责链模式
本系列将持续更新,喜欢的小伙伴可以点一下关注和推荐,谢谢大家的支持
努力,不是为了要感动谁,也不是要做给哪个人看,而是要让自己随时有能力跳出自己厌恶的圈子,并拥有选择的权利。记住,用自己喜欢的方式过一生。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?