定义
命令模式:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
UML图
说明:- Invoker 是命令的执行者,通过调用Command中的execute()方法执行命令。
- Receiver 是一个接收者,接收着定义了一系列可以执行的动作。
- ConcreteCommand 是由抽象的Command派生出来的,实现了Command定义的execute() 方法。每一个ConcreteCommand通过持有Receiverd调用者对象,从而调用Reveriver的方法来完成任务。
- Client 负责的是生成Receriver,具体的ConcreteCommand,然后将Receiver传递到对应的ConcreteCommand中。
- 动作的执行过程,也是由Client生成一个Invoker对象,再将组装好的ConcreteCommand传递到Invoker中,调用Invoker中的方法执行动作。
命令模式中的undo
命令模式中的Undo撤销操作,Invoker调用者中持有Command undoCommand 的变量,保存上一次执行命令的Command对象实例,Client调用undo操作的时候,通过调用undoCommand的undo()方法,进而指定该Command实例注入的接收者执行对应的撤销操作。从而完成undo操作。
命令模式宏操作
Client 中通过将一组命令进行绑定的操作,如生成
Command[] partyOn = { lightOn, stereoOn, tvOn, hottubOn};
对应数据结构,从而完成对指定命令的Command的执行过程。命令模式的更过用途
队列请求:命令模式可以将运算打包(一个接收者和一组动作)然后将它传来传去,就像是一般的对象一样。现在,即使在对象背创建很久之后,依然可以被调用。事实上,它甚至可以在不同的线程中被调用。可以利用这些特性衍生一些应用,例如:日程安排,线程池,工作队列等。
一个工作队列,在某一端添加命令,另一端是线程。线程执行动作:从队列中取出一个命令,调用它的execute() 方法,然后等待这个调用完成,然后将此命令对象丢弃,再取出下一个命令。。。。
其中:工作队列类和计算对象之间是完全解耦的。某一个时间段,线程在进行A任务,另一个时间段可能进行B任务。工作队列需要做的是:取出命令对象,然后调用命令对象的execute()方法。同样的,只要是实现了命令模式的对象,就可以放在队列中,当线程可用的时候,就调用此对象的execute()方法。日志请求:对某些应用我们需要将所有的动作都记录在日志中,并能在系统死机之后,重新调用这些动作恢复到之前的状态。通过两个方法(Store() 和 load()),命令模式可以支持这一点。在Java中,我们可以利用对象的序列化实现这些方法,但是一般认为序列化最好还是只用在对象的持久化上。
也就是,在我们执行命令的时候,将历史记录记载在磁盘上。一旦系统死机,我们就将这些命令重新加载,并成批次的调用这些对象的execute() 方法。
个人理解
1、命令模式将发出请求的对象和执行请求的对象解耦。
2、在被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接收者和一个或多个动作。
3、通过调用命令对象的execute()方法,发出请求,这会使得接收者的动作被调用。
4、调用者可以接收命令当做参数,甚至在运行时动态地进行。
5、命令模式可以支持撤销操作,做法是实现一个undo()方法来回到execute()被执行前的状态。
6、宏命令是命令的一种简单的延伸,允许调用多个命令。宏方法也可以支持撤销操作。
7、实际操作过程中,很常见的用“聪明”命令对象,也就是直接实现了请求,而不是将工作委托给接受者。
8、命令模式可以用来实现日志和事务请求。