命令模式:
命令模式把请求封装为对象,以便用不同的请求、队列或者日志请求来参数化其他对象,并支持可撤销的操作。
NoCommand:
Nocommand是一个**空对象(null object)**的例子。当你不想返回一个有意义的对象时,以及你要把处理null的责任从客户移除时,空对象就很有用。例如,在我们的遥控器中,没有一个有意义的对象来分配给每个槽,因此我们提供一个NoCommand对象作为替身,在excute()方法被调用时,不做任何事情。
你会发现在许多设计模式相关的内容中用到了空对象,有时你甚至会看到"空对象"出现在设计模式列表中。
宏命令:
在宏命令(MacroCommand) 中,用命令数组储存一大群命令。
当宏被遥控器执行时,一次性执行这些命令。
问: 一定需要接收者 吗?为什么不能让命令对象实现execute()方法的细节?
答: 一般来说,我们尽量争取制作**"哑"命令对象** ,它只调用接收者上的一个动作;但是,有很多"聪明"命令对象 的例子,它们实现大多数(如果不是全部的话)履行请求所需的逻辑。无疑,你可以这样做,只是要牢记,调用者和接收者之间不再有同样级别的解耦,你也不能用接收者来参数化命令。
问: 我怎样才能实现撤销操作的历史?换句话说,我要能够多次按下撤销按钮。
答: 很棒的问题。其实相当容易,不只是保持一个到上一个已执行命令的引用,而是保持一个之前命令的堆栈 。然后,无论何时按下撤销,调用者把第一项弹出栈,并调用其undo()方法。
问: 通过创建一个PartyCommand,并把执行其**他命令的调用放进PartyCommand的execute()**方法中,我把party模式实现为一个命令,这样可以吗?
答: 可以,但是本质上这是**"硬编码"party模式** 到PartyCommand,干吗要自找麻烦呢?有了宏命令,你可以动态地决定哪一个命令进入宏命令,因此,使用宏命令有更多弹性。一般来说,宏命令是更加优雅的解决方案,代码更少。
命令模式的更多用途:请求队列
命令把一小块计算打包(一个接收者和一组动作 ),然后把它作为头等对象传来传去 。即使在一些客户应用创建命令对象很久之后,计算自身依然可能被调用 。事实上,甚至可以被不同的线程调用。
命令模式的更多用途:日志请求
当我们执行命令时,把历史储存在磁盘中 。一旦出现崩溃,就重新加载命令对象,并成批地依次调用它们的execute()方法。
这种记录日志的方式对遥控器来说没有意义,但是,有很多应用调用大型数据结构的动作,不能每一次出现变化都快速保存。通过记录日志,我们可以保存上次检查点之后的所有操作 ,如果系统出状况,把这些操作应用到检查点。
要点:
- 命令模式把做出请求的对象 从知道如何执行请求的对象解耦。
- 命令对象处在解耦的中心,封装接收者以及一个(或一组)动作。
- 调用者通过调用命令对象的execute()做出请求,这会使得接收者的动作被调用。
- 调用者可以用命令参数化 ,甚至可以在运行时动态地进行。
- 通过实现一个undo()方法 来把对象重建 到最后一次执行execute()前的状态,命令可以支持撤销。
- 宏命令 是命令模式的一种简单的延申。它允许调用多个命令。同样,宏命令很容易支持undo()。
- 在实践中,"聪明"命令对象 并不少见。这些对象自己实现请求,而不是委托给接收者。
- 命令也可以用来实现日志和事务系统。