命令模式
1、命令模式的动机
动机:将请求者和接受者进行解耦,发送者与接受者没有直接的引用关系,发送者只需要知道如何发送请求,而不必关注 有那个接受者来执行请求;
2、命令模式的定义
命令模式将”请求”封装成对象,以便使用不同的请求,队列或者日志来参数化其他对象,命令模式支持可撤销的操作。
请求即是命令,命令中封装了动作和接受者,对外之暴露execute()执行方法。
3、命令模式的类结构图
分析如下:
- 命令模式本质就是封装命令,将命令的请求者和命令的执行者分割开来;
- 请求的一方发出后,要求执行一个操作,而接受者接受到这个请求,调用具体的一组动作来完成这个操作;
- 请求者不知道具体的接受者,不知道接受者是否执行了命令,是否完成了命令;
- 命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联;
4、优缺点和适用场景
优点:
- 降低系统的耦合度;
- 新的命令可以很容易地加入到系统中;
- 可以比较容易地设计一个命令队列和宏命令(组合命令);
- 可以方便地实现对请求的Undo和Redo。
缺点:
- 导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。
适用场景:
- 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
- 系统需要在不同的时间指定请求、将请求排队和执行请求。
- 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
- 系统需要将一组操作组合在一起,即支持宏命令。
5、实例
例:设计一个遥控器,既可以控制电扇,电灯的打开关闭,也可以撤销之前的命令,以及统一操作;
类图:
命令接口:
public interface Command {
void excute();
void undo();
}
电灯接口及实现:
public interface Light {
void off();
void on();
}
public class DropLight implements Light {
public void off() {
System.out.println("关掉吊灯");
}
public void on() {
System.out.println("打开吊灯");
}
}
电扇接口及实现:
public interface Fan {
void off();
void on();
}
public class DropFan implements Fan {
public void off() {
System.out.println("关闭吊扇");
}
public void on() {
System.out.println("打开吊扇");
}
}
具体命令:
@AllArgsConstructor
public class OffFanCommand implements Command {
private Fan fan;
public void excute() {
fan.off();
}
public void undo() {
fan.on();
}
}
@AllArgsConstructor
public class OnFanCommand implements Command {
private Fan fan;
public void excute() {
fan.on();
}
public void undo() {
fan.off();
}
}
@AllArgsConstructor
public class OffLightCommand implements Command {
private Light light;
public void excute() {
light.off();
}
public void undo() {
light.on();
}
}
@AllArgsConstructor
public class OnLightCommand implements Command {
Light light;
public void excute() {
light.on();
}
public void undo() {
light.off();
}
}
public class UnifyCommand implements Command {
List<Command> commands = new ArrayList<Command>();
public void setCommand(Command command) {
commands.add(command);
}
public void excute() {
for(Command command : commands) {
command.excute();
}
}
public void undo() {
for(Command command : commands) {
command.undo();
}
}
}
调用者类即遥控器类:
public class RemoteControl {
private Command[] onCommands;
private Command[] offCommands;
private Command preCommand;
public RemoteControl() {
onCommands = new Command[3];
offCommands = new Command[3];
for(Command command : offCommands) {
command = new NoCommand();
}
for(Command command : onCommands) {
command = new NoCommand();
}
}
public void setCommands(int i, Command offCommand, Command onCommand) {
onCommands[i] = onCommand;
offCommands[i] = offCommand;
}
public void offLightButton() {
offCommands[0].excute();
preCommand=offCommands[0];
}
public void onLightButton() {
onCommands[0].excute();
preCommand = onCommands[0];
}
public void offFanButton() {
offCommands[1].excute();
preCommand = offCommands[1];
}
public void onFanButton() {
onCommands[1].excute();
preCommand = onCommands[1];
}
public void unifyOnButton() {
onCommands[2].excute();
preCommand = onCommands[2];
}
public void unifyOffButton() {
offCommands[2].excute();
preCommand = offCommands[2];
}
public void revocation() {
preCommand.undo();
}
}
客户端类,test:
public class Test {
public static void main(String[] args) {
RemoteControl control = new RemoteControl();
Light light = new DropLight();
Fan fan = new DropFan();
// 设置电灯控制命令
control.setCommands(0,new OffLightCommand(light),new OnLightCommand(light));
// 设置电扇控制命令
control.setCommands(1, new OffFanCommand(fan), new OnFanCommand(fan));
// 设置统一命令
UnifyCommand onUnifyCommand = new UnifyCommand();
onUnifyCommand.setCommand(new OnLightCommand(light));
onUnifyCommand.setCommand(new OnFanCommand(fan));
UnifyCommand offUnifyCommand2 = new UnifyCommand();
offUnifyCommand2.setCommand(new OffLightCommand(light));
offUnifyCommand2.setCommand(new OffFanCommand(fan));
control.setCommands(2, offUnifyCommand2, onUnifyCommand);
//打开电灯
control.onLightButton();
//打开电扇
control.onFanButton();
//同时关闭电灯电扇
control.unifyOffButton();
//撤销上次动作
control.revocation();
}
}