命令模式
- 命令模式的定义
- 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作
- Command:定义命令的接口,声明执行的方法
- ConcreteCommand:命令接口实现对象,是’虚’的实现;通常会持有接受者,并调用接收者的功能来完成命令要执行的操作
- Receiver:接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要他能够实现命令要求实现的相应功能
- Invoker:要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口
- Client:创建具体的命令对象,并且设置命令对象的接收者。注意这个不是我们常规意义上的客户端,而是在组装命令对象和接收者,或许,把这个Client称为装配者会更好理解,因为真正使用命令的客户端是从Invoker来触发执行
/* 命令接口,声明执行的操作 */ public interface Command { /* 执行命令对应的操作 */ public void execute(); } /* 具体的命令实现对象 */ public class ConcreteCommand implements Command { /* 持有相应的接收者对象 */ private Receiver receiver = null; /* 示意,命令对象可以有自己的状态 */ private String state; /* 构造方法,传入对应的接收者对象 @param receiver 相应的接收者对象 */ public ConcreteCommand(Receiver receiver) { this.receiver = receiver; } public void execute() { receiver.action(); } } /* 接收者对象 */ public class Receiver { /* 示意方法,真正执行命令相应的操作 */ public void action() { // 真正执行命令操作的功能代码 } } /* 调用者 */ public class Invoker { /* 持有命令对象 */ private Command command = null; /* 设置调用者持有的命令对象 @param command 命令对象 */ public void setCommand(Command command) { this.command = command; } /* 示意方法,要求命令执行请求 */ public void runCommand() { // 调用命令对象的执行方法 this.command.execute(); } } public class Client { /* 示意,负责创建命令对象,并设定他的接收者 */ public void assemble() { // 创建接收者 Receiver receiver = new Receiver(); // 创建命令对象,设定他的接收者 Command command = new ConcreteCommand(receiver); // 创建Invoker,把命令对象设置进去 Invoker invoker = new Invoker(); invoker.setCommand(command); } }
- 命令模式的关键
- 把请求封装成为对象,也就是命令对象,并定义了统一的执行操作的接口,这个命令对象还可以被存储、转发、记录、处理、撤销等,整个命令模式都是围绕这个对象在进行
- 命令模式的组装和调用
- 在命令模式中经常会有一个命令的组装者,用它来维护命令的虚实现和真是实现之间的关系。如果是超级智能的命令,也就是说命令对象自己完全实现好了,不需要接收者,那就是命令模式的退化,不需要接收者,自然也不需要组装者了
- 真正的用户就是具体实现请求的内容,然后提交请求进行触发就可以了。真正的用户会通过Invoker来触发命令
- 在实际开发过程中,Client和Invoker可以融合在一起,由客户在使用命令的时候,先进行命令对象和接收者的组装,组装完成后,就可以调用命令执行请求
- 命令模式的接收者
- 接收者可以是任意的类,对它没有什么特殊要求,这个对象知道真正执行命令的操作,执行时是从Command的实现类里面调转过来
- 命令模式的优点
- 更松散的耦合
- 更动态的控制
- 更自然的复合命令
- 更好的扩展性
- 命令模式的本质
- 封装请求
- 何时选用命令模式
- 如果需要抽象出需要执行的动作,并参数化这些对象,可以选用命令模式。将这些需要执行的动作抽象成为命令,然后实现命令的参数化配置
- 如果需要在不同的时刻指定、排列和执行请求,可以选用命令模式。将这些请求封装成为命令对象,然后实现将请求队列化
- 如果需要支持取消操作,可以选用命令模式,通过管理命令对象,能够很容易地实现命令的恢复和重做功能
- 如果需要支持当前系统崩溃时,能将系统的操作功能全部重新执行一遍,可以选用命令模式。将这些操作功能的请求封装成命令对象,然后实现日志命令,就可以在系统恢复以后,通过日志获取命令列表,从而重新执行一遍功能
- 在需要事务的系统中,可以选用命令模式。命令模式提供了对事务进行建模的方法。命令模式有一个别名就是Transaction