设计模式笔记_六_命令模式

命令模式

命令模式 将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。

  • 封装调用

    通过封装方法调用,可以把运算块包装成形。所以调用此运算的对象不需要关心事情是如何进行的,只要知道如何使用包装成形的方法来完成它就可以。
    通过封装方法调用,也可以做一些很聪明的事情,比如:记录日志、重复使用这些封装来实现撤销。
  • 命令模式可将“动作的请求者”从“动作的执行者”对象中解耦。利用命令对象,把请求封装成一个特定对象。

一个命令对象通过在特定接受者上绑定一组动作来封装一个请求。要达到这一点,命令对象将动作和接受者包进对象中。这个对象只暴露出一个execute()方法。此方法被调用的时候,接受者就会进行这些动作。

类图

总结

基础

  • 抽象

  • 封装

  • 多态

  • 继承

原则

  • 封装变化

  • 多用组合,少用继承

  • 针对接口编程,不针对实现编程

  • 为交互对象之间松耦合设计而努力

  • 类应该对扩展开放,对修改关闭

  • 依赖抽象,不要依赖具体类

要点

  • 命令模式将发出请求的对象和执行请求的对象解耦

  • 在被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接受者和一个或一组动作

  • 调用者通过调用命令对象的execute()发出请求,这会使得接受者的动作被调用

  • 调用者可以接受命令当做参数,甚至在运行时动态地进行

  • 命令可以支持撤销,做法是实现一个undo()方法来回到execute()被执行前的状态

  • 宏命令是命令的一种简单的延伸,允许调用多个命令。宏方法也可以支持撤销

  • 命令模式也可以用来实现日志和事务系统

案例

遥控器

先来看一下遥控器的样子

我们想让我们的遥控器适应五花八门厂商生产的各种产品(比如,电视、电灯、车库门等)。不同产品的方法又各有不同,比如点灯有on(),off(), TV除了开关,还有setVolumn()等。

利用命令对象,把请求(例如打开电灯)封装成一个特定对象(例如客厅电灯对象)。所以对每个按钮都存储一个命令对象,那么当按钮被按下的时候,就可以请命令对象做相关的工作。遥控器并不需要知道工作内容是什么,只要是个命令对象能和正确的对象沟通,把事情做好就可以了。这样,遥控器和电灯对象解耦了。

使用这个模式,能够创建一个API,将这些命令对象加载到按钮插槽,让遥控器的代码尽量保持简单。而把家电自动化的工作和进行该工作的对象一起封装在命令对象中。

再以餐厅为例

餐厅的女招待通过订单和厨师解耦。

命令模式允许将“发出请求的对象”和“接受与执行这些请求的对象”分隔开来。比方说,对于遥控器API,我们需要分隔开“发出请求的按钮代码”和“执行请求的厂商特定对象”。万一遥控器的每个插槽都持有一个像餐厅订单那样的对象,那么,当一个按钮被按下,只要调用该对象的orderUp()方法,点灯就开了,而遥控器不需要知道事情是怎么发生的,也不需要知道设计哪些对象。

从餐厅到命令模式

角色对应关系:

  • 女招待:Invoker

  • 快餐厨师:Receiver

  • orderUp()execute()

  • 订单:Command

  • 顾客:Client

  • takeOrder()setCommand()

实现命令接口

实现一个打开点灯的命令

使用命令对象

简单测试

输出

实现遥控器

再次测试遥控器

输出

最后更新于