参考书——《HeadFirst设计模式》
命令模式最关键的点——将“请求”封装成对象。使得发出请求的对象(Invoker)和接受与执行这些请求的对象(Receiver)分隔开来。
定义:将”请求“封装成对象,以便使用不同的请求、队列、日志来参数化其他对象。命令模式也支持可撤销的操作。
一个命令对象通过在特定接受者上绑定一组动作来封装一个请求。要达到这一点,命令对象将动作和接受者包进对象中,这个对象只暴露一个execute()方法,此方法被调用的时候,接受者就会进行这些动作。
Invoker调用者持有一个命令对象,并在某个时间点调用命令对象的execute()方法,将请求付诸实行。
Command为所以命令声明了一个接口。调用命令对象的execute()方法,就可以让接受者执行相关的动作。这个接口也具备一个undo()方法。
ConcreteCommand定义了动作和接受者之间的绑定关系。调用者只要调用execute()就可以发出请求,然后由ConcreteCommand调用接受者一个or多个动作。
Receiver知道如何进行必要的工作,实现请求。
应用场景
在下面的情况下应当考虑使用命令模式:
1)使用命令模式作为"CallBack"在面向对象系统中的替代。(P.s:对于回调的理解——回调是对接口而言。简单来说就是,A对象调用了自己的方法a,方法a接收的参数是B接口的实例b,而在方法a中将执行b的方法c。)
2)需要在不同的时间指定请求、将请求排队。一个命令对象和原先的请求发出者可以有不同的生命期。换言之,原先的请求发出者可能已经不在了,而命令对象本身仍然是活动的。这时命令的接收者可以是在本地,也可以在网络的另外一个地址。命令对象可以在串形化之后传送到另外一台机器上去。
3)系统需要支持命令的撤消(undo)。命令对象可以把状态存储起来,等到客户端需要撤销命令所产生的效果时,可以调用undo()方法,把命令所产生的效果撤销掉。命令对象还可以提供redo()方法,以供客户端在需要时,再重新实施命令效果。
4)如果一个系统要将系统中所有的数据更新到日志里,以便在系统崩溃时,可以根据日志里读回所有的数据更新命令,重新调用execute()方法一条一条执行这些命令,从而恢复系统在崩溃前所做的数据更新。