命令模式
1.模式动机与定义
模式动机
- 按钮 ← → 请求发送者
- 事件处理类 ← →请求的最终接收者和处理者
- 发送者与接收者之间引入了新的命令对象(类似电线),将发送者的请求封装在命令对象中,再通过命令对象来调用接收者的方法
- 相同的按钮可以对应不同的事件处理类
模式定义
- 命令模式(Command Pattern):将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。
- 命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式
2.模式结构与分析
模式结构
命令模式包含如下角色
- Command:抽象命令类:一般是一个接口,在其中声明了用于执行请求execute方法等,通过这些方法可以调用请求接收者的相关操作
- ConcreteCommand:具体命令类:是抽象命令类的子类,实现了在抽象命令类中声明的方法,对应具体的接收者对象,绑定接收者对象的动作。在实现execute方法时,将调用接收者对象的相关操作Action
- Invoker: 调用者:调用者即请求的发送者,请求者,通过命令对象来执行请求。在程序运行时将调用具体命令对象的execute方法,间接调用接收者的相关操作。
- Receiver:接收者:接收者执行与请求相关的操作,具体是实现对请求的业务处理
- Client: 客户类:在客户类中需要创建发送者对象和具体命令类对象,在创建具体命令对象时指定其对应的接收者,发送者和接收者之间无直接关系,通过具体命令对象实现间接调用
模式分析
- 将请求发送者和接收者完全解耦
- 发送者与接收者之间没有直接引用关系
- 发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求
- 命令模式的本质是对请求进行封装
- 一个请求对应于一个命令,将发出命令的责任和执行命令的责任分开
//调用者(请求发送者)示例代码
public class Invoker {
private Command command;
//构造注入
public Invoker(Command command){
this.command=command;
}
//设值注入
public void setCommand(Command command){
this.command=command;
}
//业务方法,用于调用命令类的execute()方法
public void call(){
command.execute();
}
}
//具体命令类示例代码
public class ConcreteCommand extends Command{
private Receiver receiver; //维持一个对请求接收者对象的引用
public void execute(){
receiveraction();//调用请求接收者的业务处理方法action()
}
}
- 命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开
- 每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行操作。
- 命令模式允许请求的一方和接收的一方独立开来使得请求的一方不必知道接收请求的一方的接口更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。
- 命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。
- 命令模式的关键在于引入了抽象命令接口且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。
3.模式效果与应用
优点
- 降低系统的耦合度
- 新的命令可以很容易地加入到系统中,符合开闭原则
- 可以比较容易地设计一个命令队列或宏命令(组合命令)
- 为请求的撤销(Undo)和恢复(Redo)操作提供了一种设计和实现方案
缺点
使用命令模式可能会导致某些系统有过多的具体命令类(针对每一个对请求接收者的调用操作都需要设计一个具体命令类)
使用情况
- 需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互
- 需要在不同的时间指定请求、将请求排队和执行请求
- 需要支持命令的撤销(Undo)操作和恢复(Redo)操作
- 需要将一组操作组合在一起形成宏命令
模式应用
- Java语言使用命令模式实现AWT/Swing GUI的委派事件模型(Delegation Event Model, DEM)
- 很多系统都提供了宏命令功能,如UNIX平台下的Shell编程,可以将多条命令封装在一个命令对象中,只需要一条简单的命令即可执行一个命令序列这也是命令模式的应用实例之一。
模式扩展
- 宏命令又称为组合命令,它是命令模式和组合模式联用的产物。
- 宏命令也是一个具体命令,不过它包含了对其他命令对象的引用,在调用宏命令的execute(方法时,将递归调用它所包含的每个成员命令的execute()方法,一个宏命令的成员对象可以是简单命令,还可以继续是宏命令。执行一个宏命令将执行多个具体命令,从而实现对命令的批处理。
浙公网安备 33010602011771号