一、命令(Command)模式的结构
命令模式把一个请求或者操作封装到一个对象中。命令模式允许系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。
命令模式是对命令的封装。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。命令模式类似C语言的回调。因为java不支持函数指针,所以命令模式可以达到同样的目的。
结构图如下图所示:
客户角色代码如下:
public class Client{
public static void main(String [] args){
Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker(command);
invoker.action();
}
}
一个具体命令与一个接收者绑定,在具体命令里面调用接收者的处理方法,而客户端的请求可以调用不同的命令对象。如果要增加一个新的命令,只需要增加新的具体命令对象和接收者,而不需要改动客户端代码,客户端也不会察觉。
二、 命令模式在java中的应用
AWT的事件处理
Java语言使用了命令模式处理java.awt库的事件委派处理模型。在这个事件处理模型里面,命令对象实现AWT的listener接口,相当于命令接口。为把一个命令对象与一个AWT构件连接起来,需要把它登记成一个事件的listener。构件认识listener接口,而不在乎接口是怎么实现的。换言之,AWT构件不在意命令所代表实现操作。
三、 命令模式的使用场景
命令模式优缺点
优点:(1)命令模式使新的命令很容易地被加入到系统里(2)允许接收请求的一方决定是否要否决请求(3)能较容易的设计一个命令队列(4)可以容易的实现对请求的Undo和Redo(5)在需要的情况下,可以较容易地将命令记入日志。
适合的情况
1、使用命令模式作为“回调”在面向对象系统中的替代。“回调”讲的便是先将一个函数登记上,然后在以后调用此函数。
2、需要在不同的时间指定请求、将请求排队。一个命令对象和原先的请求发出者可以有不同的生命期。这时命令的接收者可以是在本地,也可以在网络的另外一个地址。
3、系统需要支持命令的撤消。命令对象可以把状态存储起来,等到客户端需要撤消命令所产生的效果时,可以调用undo()方法撤销。命令对象还可以提供redo()方法,以供客户端在需要时,再重新实施命令的效果。
4、如果一个系统要将系统中所有的数据更新到日志里,以便在系统崩溃时,可以根据日志里读回所有的数据更新命令,重新调用execute()方法一条一条执行这些命令,从而恢复系统在崩溃前所做的数据更新。
5、一人系统需要支持交易(transaction)。一个交易结构封装了一组数据更新命令。使用命令模式实现交易结构可以使系统增加新的交易类型。
四、 命令模式与其他模式的关系
命令模式与合成模式
合成模式可以应用到命令类的合成上,从几个具体命令类合成宏命令类。可以在任何需要的时候重新把这些记录下来的命令一次性执行,这就是所谓的宏命令集功能。
备忘录模式
如果命令需要撤销和恢复功能的话,备忘录模式可以用来存储关于命令的效果状态信息。
五、 Swing库中的命令撤销和恢复
Swing在javax.swing.undo库里提供了撤销和恢复的系统化处理方法。javax.swing.undo库虽然是Swing库的一部分,但它既可以与Swing构件一起使用,又可以与AWT构件一起使用。
每一个命令或操作在Swing里都叫做一个编辑(Edit)。每一个可撤销的命令与操作在Swing里都叫做一个可撤销编辑。
(1)接口UndoableEdit。一个类如果需要有撤销和恢复功能的话,就需要实现UndoableEdit接口。
(2)抽象类AbstractUndoableEdit是对UndoableEdit接口的最小实现,也是javax.swing.undo库里其他类的基类。
(3)接口StateEditable是所有类的可以编辑的类必须实现的接口。
(4)SateEdit类代表一个可编辑类的状态
(5)UndoManager类负责管理所有的对一个可编辑类的编辑。