烤羊肉串引来的思考——命令模式

    夏日的夜晚,大街上总是热闹非凡,人们都喜欢约三五好友去吃烧烤喝啤酒,所谓吃着烤串儿,还唱着歌儿,那感觉就一个字——爽。

 

    在街上溜达,突然发现一个烧烤摊人不多,于是你就上前对老板说:来10串羊肉串,3串鸡翅……。说完之后,你就站在边上等,这时你发现,人越来越多,之间大家七嘴八舌跟老板说自己的要求,明显看到老板有些手足无措。首先老板要记住谁先来的谁后来的,谁给钱了谁没给钱,谁不要放辣椒……等等,太多的问题接踵而至,而且那么多人都在那里盯着老板烤串,这样就引起了挑剔,哪一串多了,哪一串少了什么的,真的很是混乱。

    于是你你选择了去不远处的一家烧烤店,坐下后,直接给服务员说了自己要吃什么吃多少,服务员在订单上记下之后,直接将订单送往后厨,然后招待其他刚进来的顾客。作为一个程序员的你,此时此刻陷入了沉思……

    今晚这两种情况恰好说明了一个软件设计中设计模式,就是标题提到的命令模式,我们来看看如何将现实情况映射到命令模式。

首先第一种情况,烧烤摊的经营模式我们可以对其进行抽象,得到如下类图:


     结构图很简单,就两个类,但是正因为简单,其隐含的问题就太多了.单纯地从编程的角度看,客户是"行为的请求者",而烤串老板即为"行为的实现者",上面的那种情况下,两者的耦合性很高,这在编程中是大忌,而且如果行为请求者要撤销自己的请求,这种紧耦合的关系实在是很麻烦.那么如何改进呢?

我们再来看看对烧烤店的情况进行的抽象,其结构图如下:


     从上面的类图中可以看到,我们加入了一个服务员类,从而使客户和烤串者解耦合,服务员一方面要从客户那里接受订单,另一方面就是通知后厨师傅执行客户的要求.我们结合具体的代码实现来说明类图中的关系时如何在代码中实现的,至于第一个类图的代码实现由于比较简单,就留给读者去实现吧,这里不再赘述.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    //客户端代码实现
    class Program
    {
        static void Main(string[] args)
        {
            //开店前的准备
            Barbecuer boy = new Barbecuer();
            Command bakeMuttonCommand1 = new BakeMuttonCommand(boy);
            Command bakeChickenWingCommand1 = new BakeChickenWingCommand(boy);
            Waiter girl = new Waiter();

            //开门营业,顾客点菜
            girl.SetOrder(bakeMuttonCommand1);
            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();
    //    }
    //}
    //改写后的服务员类*******************************************************************************
    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();
            }
        }
    }
}

     首先我们看服务员类和抽象命令类之间是聚合关系,为什么呢?很简单就是服务员可以接受各种各样的命令,而服务员和各个命令类各自是相互独立的,因此是一种聚合关系.代码中我们在服务员类中声明一个存放具体命令的容器(List类型),然后将具体的命令类的实例作为其方法的参数,以便对其进行操作.

     其次是抽象命令类和具体的命令类之间的继承关系,这个很简单应该不用多少了,就是在创建具体类的时候在类名的后面加上:后跟上父类类名(C#语言).

     再者是烤肉串者和具体命令类之间的依赖关系,这个我们在定义具体类的时候,类的构造方法的参数设为烤串者,这样就表达了,具体命令类的执行要依赖于具体的实现者,然后在方法体中通过烤串者类的实例对象调用烤串者的方法,完成具体命令要求的行为和操作.

     最后是客户端类和服务员类以及烤肉串者类之间的关联关系,这种关系是通过在客户端类中添加服务员类和烤串者类的引用来表现的,就是在客户端的代码中实例化一个烤串者类的具体对象和一个服务员类的具体对象.

     以上就是类图中各种关系在代码中的实现方法,我们可以用这样的方式去分析其他设计模式的结构图中的各种关系,这样我们在类图和代码之间的转换就会游刃有余,胸有成竹了.

   最后给出命令模式的定义:将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。我们可以对照上面的例子来理解命令模式的定义,这样就能够形象的理解命令模式到底是怎么一回事了。

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值