命令模式:将一个请求封装为一个对象,从而使我们可以用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。
命令模式包含如下角色:
-
Command: 抽象命令类
声明用于执行请求的 execute 等方法,通过这些方法可以调用接收者的相关操作
-
ConcreteCommand: 具体命令类
实现在抽象命令类中声明的方法,它对应具体的接收者对象,将接收者的动作绑定其中。
-
Invoker: 调用者
调用者即请求的发送者,又称为请求者,它通过命令对象来执行请求。
-
Receiver: 接收者
接收者执行与请求相关的操作,它具体实现对请求的业务处理。
Client: 客户类
举个例子:遥控器控制电视的开关,我们把开和关的命令封装起来。遥控器只知道开关的命令,电视机只会响应开关,这样就做到了解耦。
/**
* @author Richie on 2018.03.15
* 电视机控制命令,抽象命令角色
*/
public interface ICommand {
/**
* 执行命令
*/
void execute();
}
/**
* @author Richie on 2018.03.15
* 电视机,接收者角色
*/
public class Television {
public void turnOn(){
System.out.println("Turn on television");
}
public void turnOff(){
System.out.println("Turn off television");
}
}
/**
* @author Richie on 2018.03.15
* 打开命令,具体命令角色
*/
public class TurnOnCommand implements ICommand {
private Television television;
public TurnOnCommand(Television television) {
this.television = television;
}
@Override
public void execute() {
television.turnOn();
}
}
/**
* @author Richie on 2018.03.15
* 关闭命令,具体命令角色
*/
public class TurnOffCommand implements ICommand {
private Television television;
public TurnOffCommand(Television television){
this.television = television;
}
@Override
public void execute() {
television.turnOff();
}
}
/**
* @author Richie on 2018.03.15
* 遥控器,调用者角色
*/
public class RemoteControl {
private ICommand command;
public RemoteControl(ICommand command){
this.command = command;
}
public void setCommand(ICommand command) {
this.command = command;
}
public void turnOnTv(){
command.execute();
}
public void turnOffTv(){
command.execute();
}
}
public static void main(String[] args){
Television television = new Television();
TurnOnCommand turnOnCommand = new TurnOnCommand(television);
RemoteControl remoteControl = new RemoteControl(turnOnCommand);
remoteControl.turnOnTv();
TurnOffCommand turnOffCommand = new TurnOffCommand(television);
remoteControl.setCommand(turnOffCommand);
remoteControl.turnOffTv();
}
命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分开。命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。
优点: 在于降低系统的耦合度,增加新的命令很方便,而且可以比较容易地设计一个命令队列和宏命令,并方便地实现对请求的撤销和恢复。
缺点: 在于可能会导致某些系统有过多的具体命令类。
使用场景: 需要将请求调用者和接收者解耦,使得调用者和接收者不直接交互;需要在不同的时间指定请求、将请求排队和执行请求;需要支持命令的撤销操作和恢复操作,需要将一组操作组合在一起,即支持宏命令。