1、概要
该模式把一个请求或者操作封装到一个对象中。把发出命令和执行命令分隔开,委派给不同的对象。因为把各种命令封装成了一个一个的对象,所以可以灵活地对命令进行管理。比如:Undo和Redo。
2、什么时候需要使用Command设计模式?
- 需要实现Undo/Redo功能的时候
- 有的系统需要在数据更新的同时,把更新日志记录下来,如果系统崩溃,可以根据日志信息里记录下来的命令,重新执行系统崩溃前做的操作,从而恢复系统崩溃前做的数据更新
3、命令模式涉及到的角色
客户(Client)角色:
・命令的发出者,把接收者指定给具体命令对象
・把具体命令对象指定给Invoker,并通过调用Invoker的接口方法来发出执行命令的请求
请求者(Invoker)角色:
・相当于连接客户对象和命令对象之间的桥梁,可以想象成控制电视机的遥控器
・负责调用命令对象提供的方法,执行请求
抽象命令(Command)角色:
・所有具体命令类的父类,为了使用运行时多态
具体命令(ConcreteCommand)角色:
・封装具体命令的类
・调用Receiver的方法,执行请求
接收者(Receiver)角色:
・请求和操作的实际执行者
这五种角色的关系可以理解为上下级关系:
- 客户是最高级,它负责协调其他角色之间的关系,并发布命令,比如:把接收者委派给具体命令来管理,把具体命令委派给Invoker去管理
- 请求者管理具体命令,向具体命令发布命令
- 具体命令管理接收者,并向接收者下达命令
- 接收者是最低级,它只能接收命令,并执行具体的操作
示例代码:
相当于人通过遥控器控制电视机的打开和关闭,并实现了简单的Undo和Redo功能。
每次执行完一个命令的时候,把命令句柄保存起来,Redo的时候,直接调用doCmd.execute方法即可;
Undo的时候,直接调用doCmd的undo方法即可。Redo相对简单一些,因为只要重做前一次的操作即可。
public class CommandTest{
public static void main(String[] args){
Tvset tv = new Tvset();
TurnonCommand cmdOn = new TurnonCommand(tv);
TurnoffCommand cmdOff = new TurnoffCommand(tv);
RemoteController rc = new RemoteController();
rc.setCommand(cmdOn,cmdOff);
rc.turnOn();
rc.turnOff();
rc.redo();
rc.undo();
}
}
class RemoteController{
private Command cmdOn;
private Command cmdOff;
private Command doCmd;
public void setCommand(Command cmdOn,Command cmdOff){
this.cmdOn = cmdOn;
this.cmdOff = cmdOff;
}
public void turnOn(){
cmdOn.execute();
doCmd=cmdOn;
}
public void turnOff(){
cmdOff.execute();
doCmd=cmdOff;
}
public void redo(){
System.out.println("Redo start...");
doCmd.execute();
System.out.println("Redo end.");
}
public void undo(){
System.out.println("Undo start...");
doCmd.undo();
System.out.println("Undo end.");
}
}
abstract class Command{
protected abstract void execute();
protected abstract void undo();
}
class TurnonCommand extends Command{
private Tvset tv;
public TurnonCommand(Tvset tv){
this.tv=tv;
}
public void execute(){
tv.turnOn();
}
public void undo(){
tv.turnOff();
}
}
class TurnoffCommand extends Command{
private Tvset tv;
public TurnoffCommand(Tvset tv){
this.tv=tv;
}
public void execute(){
tv.turnOff();
}
public void undo(){
tv.turnOn();
}
}
class Tvset{
public void turnOn(){
System.out.println("Tvset turn on!");
}
public void turnOff(){
System.out.println("Tvset turn off!");
}
}
执行结果:
C:\javastudy>java CommandTest
Tvset turn on!
Tvset turn off!
Redo start...
Tvset turn off!
Redo end.
Undo start...
Tvset turn on!
Undo end.
C:\javastudy>