一、概述
命令模式支持请求调用者与请求接收者之间的解耦。
用途:命令可以将元算块打包(一个接收者一组动作),然后将它传来传去,就像一般的对象一样。即使在命令对象创建许久之后依然可以被调用。事实上,这甚至可以在不同的线程中被调用。可以利用这些特性衍生出一些应用。schedule、线程池、工作队列等。工作队列:在某一段添加命令,然后另一端是线程,线程从队列中取出一个命令元素,然后执行命令元素的 execute() 方法,当该方法调用完毕之后则丢弃该命令元素。
二、类图
三、代码
需要操作的对象(电灯)
package com.scott.command.undo;
public class Light {
String location;
int level;
public Light(String location) {
this.location = location;
}
public void on() {
level = 100;
System.out.println("Light is on");
}
public void off() {
level = 0;
System.out.println("Light is off");
}
/**
* 设置电灯的亮度
*/
public void dim(int level) {
this.level = level;
if (level == 0) {
off();
}
else {
System.out.println("Light is dimmed to " + level + "%");
}
}
public int getLevel() {
return level;
}
}
命令接口
/**
* 指令接口
*
* @author Scott
*/
public interface Command {
/**
* 执行方法
*/
void execute();
}
命令的实现
package com.scott.command.undo;
public class DimmerLightOnCommand implements Command {
Light light;
int prevLevel;
public DimmerLightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
prevLevel = light.getLevel();
light.dim(75);
}
@Override
public void undo() {
light.dim(prevLevel);
}
}
package com.scott.command.undo;
public class DimmerLightOffCommand implements Command {
Light light;
int prevLevel;
public DimmerLightOffCommand(Light light) {
this.light = light;
prevLevel = 100;
}
@Override
public void execute() {
prevLevel = light.getLevel();
light.off();
}
@Override
public void undo() {
light.dim(prevLevel);
}
}
命令的控制器
package com.scott.command.undo;
/**
* 控制器
*/
public class RemoteControlWithUndo {
Command[] onCommands;
Command[] offCommands;
/** 最后一次触发的命令*/
Command undoCommand;
public RemoteControlWithUndo() {
onCommands = new Command[7];
offCommands = new Command[7];
Command noCommand = new NoCommand();
for(int i = 0; i < 7; i++) {
onCommands[i] = noCommand;
offCommands[i] = noCommand;
}
undoCommand = noCommand;
}
public void setCommand(int slot, Command onCommand, Command offCommand) {
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
/**
* 开的命令,最后将该命令赋值给最后一个指令变量中
* @param slot
*/
public void onButtonWasPushed(int slot) {
onCommands[slot].execute();
undoCommand = onCommands[slot];
}
public void offButtonWasPushed(int slot) {
offCommands[slot].execute();
undoCommand = offCommands[slot];
}
/**
* 实现指令在执行错误或者调用完毕后的反转
*/
public void undoButtonWasPushed() {
undoCommand.undo();
}
@Override
public String toString() {
StringBuffer stringBuff = new StringBuffer();
stringBuff.append("\n------ Remote Control -------\n");
for (int i = 0; i < onCommands.length; i++) {
stringBuff.append("[slot " + i + "] " + onCommands[i].getClass().getName()
+ " " + offCommands[i].getClass().getName() + "\n");
}
stringBuff.append("[undo] " + undoCommand.getClass().getName() + "\n");
return stringBuff.toString();
}
}
持有器测试
package com.scott.command.undo;
public class RemoteLoader {
public static void main(String[] args) {
RemoteControlWithUndo remoteControl = new RemoteControlWithUndo();
Light livingRoomLight = new Light("Living Room");
DimmerLightOnCommand dimmerLightOnCommand = new DimmerLightOnCommand(livingRoomLight);
DimmerLightOffCommand dimmerLightOffCommand = new DimmerLightOffCommand(livingRoomLight);
remoteControl.setCommand(0, dimmerLightOnCommand, dimmerLightOffCommand);
remoteControl.onButtonWasPushed(0);
remoteControl.offButtonWasPushed(0);
remoteControl.undoButtonWasPushed();
}
}