调侃《Head First 设计模式》之命令模式

       首先你有一个遥控器,什么样的呢?它有七个插槽,可以插上七种不同的装置,每个插槽对应两个按钮,分别对插槽的装置进行开关操作。如下图:

      

     

    现在你需要设计遥控器的API,使得遥控器可以接入某厂商的设备装置需要插到插槽上的设备的类如下图:

    

     类不少,而且以后还会增加,所以设计一个复用性和可扩展性高的遥控器API变得十分迫切。

    我们看到,厂商提供的设备类中除了有on和off方法外,还有setDirection和setVolume等等,根据之前设计模式提到的原则,隐约知道遥控器不需要知道这些类的设计具体实现,这样才可以满足扩展性要求,但是不知道具体实现,遥控器又如何完成对设备的操作呢?

     这涉及到将动作的请求者和动作执行者解耦的问题,有一个方法,你可以给遥控器按钮绑定对应的命令,当按钮按A下时,它只是执行了命令A,而命令A干啥按钮并不需要知道,而具体设备的操作由命令A确定。这种方式叫做命令模式。

    让我们通过一个常见的情景来认识命令模式:

    在餐厅点餐工作流程中,顾客将写好的订单看做一个命令,服务员接受了这个命令,然后他把订单(命令)交给厨师,厨师再根据订单(命令)去做菜。在这个情景中,顾客是动作请求者,厨师是动作执行者,二者并没有接触(解耦),但是通过命令的传递完成了整个点菜流程。

   回到遥控器,装置设备就犹如厨师,遥控者就是顾客,遥控器就类似服务员,而我们接下来就要实现类似订单的命令。看下面如何实现第一个命令对象:

  首先是命令接口,所有的命令都是实现该接口:

    

    接下来是一个打开和关闭电灯的命令:

   

   接下来是遥控器类:

   

   setCommand类似于将订单交给服务员,而buttonWashed则类似于将订单交给厨师做菜。

   客户端程序:

   

   看,Light就是厨师,on和off相当于做菜行为,LightXXCommand就是订单。通过setCommand将电灯操作命令传给遥控器,遥控器在某个时刻按下按钮调用命令的execute,而execute正是调用了Light的on和off方法,这样,遥控器和电灯的开关不就解耦了么,遥控器只知道它接受一个继承Command接口的类对象和按钮按下就调用命令的execute方法,其他的不用管,这样当引入其他装置设备时只要增加一个新的命令就行了。(是不是很high?)


   该是官方定义的时候了:

   命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也可以支持撤销操作。对象只暴露出一个execute方法,当此方法调用的时候接受者就执行相应的动作。从外面看,其他对象不知道哪个接受者进行了哪个动作,只知道如果调用execute方法,请求的目的就可以达到。


   像遥控器的例子,遥控器不在乎拥有的什么命令对象,只要对象实现了Command接口就行了。

   以下是命令模式的类图:

   


   一句话总结,Invoker得到命令对象后,在某个时刻调用特定方法(比如遥控器按钮按下)触发命令对象调用execute方法,从而调用Receiver的相应方法(比如电灯的开或关)。

   

   让我们开始遥控器的API设计吧~~

   为每个按钮绑定命令:

   

     然后是遥控器代码:

    

     用两个数组分别表示开和关两排按钮,数组下标表示按钮位置。注意到构造方法中为两个数组初始化为noCommand,noCommand是什么呢?它是一个execute方法为空的实现Command接口的类,可以叫做一个空对象,它的对象没有任何实现真正意义上的功能,它的作用是确保每个插槽都有命令,以免在插槽对应按钮被按下的时候需要对插槽是否绑定命令进行判断,容易出现调用前忘记做判断的错误。

      

    再看命令类,举一个比电灯复杂的例子,比如音响,方法稍微多了点:

    

 

    客户端代码,测试遥控器:

    

     

     

    看,遥控器只知道哪个插槽设置了什么命令,至于命令是什么,命令的接受者,它都一概不管。以后要更换插槽的控制设备,这与遥控器无关,只要增加新的命令,再绑定到遥控器按钮即可。

    对了,还有命令的撤销的实现,先实现撤销最后一步操作的功能。其实很简单,只要在相应的命令接口中添加一个undo方法就行了,undo方法执行的是和execute相反的操作。

    

    相应的命令类(例如电灯):

    

    当然电灯关的命令就是让电灯开命令的execute方法的语句和undo方法语句调换位置就行了。

    现在为遥控器代码添加了撤销最后一步的功能:

   

   

   看到多了个undoCommand的对象,它的作用是记录最后一个命令操作。当撤销按钮按下的时候便调用undoCommand的undo方法。

  我们还可以封装一个命令,让其可以执行多个命令:

   

  使用数组将命令对象们存起来,在调用execute的时候执行所有命令的execute方法。这样调用一次方法就可以一次性执行所有的命令,而且可以根据需要安排命令的顺序。

   总的来说,命令模式最大的优点就是将动作执行者和动作请求者解耦,常运用于对请求排队或者记录请求日志以及支持撤销操作。

  




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Head First设计模式》是一本设计模式学习的畅销书籍。这本书的作者以幽默风格和易于理解的语言,引导读者深入了解面向对象设计的基础知识和常见设计模式的应用。 《Head First设计模式》首先介绍了面向对象设计原则,如开闭原则、依赖倒置原则和单一职责原则等。它强调了设计模式的重要性,这些模式是在常见的软件开发场景中提供解决方案的经验总结。 接着,书中详细介绍了23个经典的设计模式,分为创建型模式、结构型模式和行为型模式三个大类。每个模式都通过生动的例子和图表进行解释,使读者能够更好地理解其应用场景和使用方法。同时,还提供了一些实际案例,帮助读者将学到的知识应用到实际项目中。 《Head First设计模式》以问题驱动的方式进行讲解,通过解决具体的问题来引导读者理解模式的思想和用法。这种方式使得学习变得更加有趣和互动,读者可以通过参与问题的解决过程来更好地理解模式的实际应用。 总的来说,这本书是一本通俗易懂的设计模式入门教材。它以轻松幽默的方式向读者介绍了设计模式的基本概念和常见应用。读者通过阅读这本书,能够对设计模式有一个清晰的理解,并能够在实际项目中灵活运用。无论是初学者还是有一定经验的开发者,都能从中收获实用的知识和提升自己的设计能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值