命令模式(22)

今天我们来讲一下命令模式。

一、案例

我们去烧烤店吃烧烤,给我们烤羊肉串和鸡翅。用简单的控制台应用程序来模拟一下。

/// <summary>
     /// 烤肉串者
     /// </summary>
     public class Barbecurer
     {
         public void BakeMutton()
         {
             Console.WriteLine("烤羊肉串!");
         }
 
         public void BakeChickenWing()
         {
             Console.WriteLine("烤鸡翅!");
         }
     }

客户端调用:

public static void Main()
         {
             Barbecurer boy = new Barbecurer();
             boy.BakeMutton();
             boy.BakeMutton();
             boy.BakeMutton();
             boy.BakeChickenWing();
             boy.BakeMutton();
             boy.BakeMutton();
             Console.ReadKey();
         }

二、演绎

1、第一步演绎

如果烧烤店里有好多人,都要了若干的烤串和鸡翅,那么,烤肉串者怎么记得谁点了什么,点了多少串呢?这样就会乱掉了。如何解决这个问题呢?我们需要服务员,需要菜单,这样就可以分清了。好,我们来修改一下我们的代码。

/// <summary>
     /// 烤肉串者
     /// </summary>
     public class Barbecurer
     {
         public void BakeMutton()
         {
             Console.WriteLine("烤羊肉串!");
         }
 
         public void BakeChickenWing()
         {
             Console.WriteLine("烤鸡翅!");
         }
     }
     //抽象命令类
     public abstract class Command
     {
         protected Barbecurer receiver;
 
         public Command(Barbecurer receiver)
         {
             this.receiver = receiver;
         }
 
         abstract public void ExcuteCommand();
     }
     //烤鸡翅命令
     class BakeChickenWingCommand : Command
     {
         public BakeChickenWingCommand(Barbecurer 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();
         }
     }

客户端调用:

public static void Main()
         {
             //开店前准备
             //烧烤店准备好烤肉厨师,服务员,菜单,就等客户上门
             Barbecurer boy = new Barbecurer();
             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.ReadKey();
         }

 2、第二步演绎

在这里,我们还有几个问题

①真实情况并不是客户点一个菜服务员就去通知厨房做一个菜,而是客户点完之后,服务员再报给厨房制作。

②如果某样菜没了,客户是不知道的,应该由服务员或者厨师来判断这个菜是否还有。

③客户点了很多东西,是需要记录下来的,以便后面结账使用。

④如果客户点完菜了,觉得点多了,需要取消几样菜。

好,针对上述问题,我们再来修改一下代码:

我们需要修改一下服务员类

//服务员
     public class Waiter
     {
         //增加存放具体命令的容器
         private IList<Command> orders = new List<Command>();
         //设置订单
         public void SetOrder(Command command)
         {
             if (command.ToString() == "MyTest.BakeChickenWingCommand")
             {
                 Console.WriteLine("鸡翅没有了,请点别的烧烤");
             }
             else
             {
                 orders.Add(command);
                 Console.WriteLine($"增加订单:{command.ToString()},时间:{DateTime.Now}");
             }
         }
         //取消订单
         public void CancelOrder(Command command)
         {
             orders.Remove(command);
             Console.WriteLine($"取消订单:{command.ToString()},时间:{DateTime.Now}");
         }
         //通知全部执行
         public void Notity()
         {
             //根据用户点好的订单通知厨房制作
             foreach (Command cmd in orders)
             {
                 cmd.ExcuteCommand();
             }
         }
     }

客户端调用:

public static void Main()
         {
             //开店前准备
             //烧烤店准备好烤肉厨师,服务员,菜单,就等客户上门
             Barbecurer boy = new Barbecurer();
             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.Notity();
             Console.ReadKey();
         }

这样,我们的问题都解决了,以上呢,其实就是用到了命令模式。

好,下面我们来总结一下命令模式:

命令模式:讲一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化对请求排队或记录请求日志,以及支持可撤销的操作。

来看一下命令模式的基本代码:

/// <summary>
     /// 声明执行操作的接口
     /// </summary>
     abstract class Command
     {
         protected Receiver receiver;
 
         public Command(Receiver receiver)
         {
             this.receiver = receiver;
         }
 
         abstract public void Execute();
     }
     /// <summary>
     /// 具体的命令操作
     /// </summary>
     class ConcreteCommand:Command
     {
         //将一个接收者对象绑定于这个动作,调用接受者相应的操作,以实现Execute
         public ConcreteCommand(Receiver receiver) : base(receiver)
         {
         }
 
         public override void Execute()
         {
             receiver.Action();
         }
     }
     //命令的接受者
     class Receiver
     {
         public void Action()
         {
             Console.WriteLine("执行请求!");
         }
     }
     //要求该命令执行这个请求
     class Invoker
     {
         private Command command;
 
         public void SetCommand(Command command)
         {
             this.command = command;
         }
 
         public void ExecuteCommand()
         {
             command.Execute();
         }
     }

客户端调用:

public static void Main()
         {
             Receiver r = new Receiver();
             Command c = new ConcreteCommand(r);
             Invoker i = new Invoker();
             i.SetCommand(c);
             i.ExecuteCommand();
             Console.ReadKey();
         }

以上就是命令模式的基本代码。

好了,命令模式今天就讲到这里,下一篇我们讲 职责链模式

 本系列将持续更新,喜欢的小伙伴可以点一下关注和推荐,谢谢大家的支持

相关推荐