6 Command Pattern
Definition¶
The Command Pattern(命令模式) encapsulates a request as an object, thereby letting you parameterize other objects with different requests, queue or log requests, and support undoable operations.
Class Diagram¶
The class diagram:
- The
Client is responsible for creating aConcreateCommand and setting itsReceiver . - The
Receiver knows how to perform the work needed to carry out the request. Any class can act as aReceiver . Command declares an interface for all commands. A command is invoked through itsexecute() method, which asks a receiver to perform an action.- The
Invoker holds a command and at some point asks the command to carry out a request by calling itsexecute method.
Example - Remote control¶
The remote control is our
- The
RemoteLoader creates a number ofCommand Objects that are loaded into the slots of the Remote Control. Each command object encapsulates a request of a home automation device. - The
RemoteControl manages a set ofCommand objects, one per button. When a button is pressed, the correspondingButtonWasPushed method on the command. - All
RemoteControl commands implement theCommand interface, which consists of one method:execute .Commands encapsulates a set of actions on a specific vendor class. The remote invokes these actions by calling theexecute() method.
public interface Command {
public void execute();
public void undo();
}
public class LightOffCommand implements Command{
private Light light;
public LightOffCommand (Light light) {
this.light = light;
}
public void execute () {
light.off();
}
public void undo() {light.on();}
}
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand (Light light) {
this.light = light;
}
public void execute () {
light.on();
}
public void undo() {light.off();}
}
public class NoCommand implements Command {
public NoCommand() { }
@Override
public void execute() { }
@Override
public void undo() { }
}
public class RemoteControl {
private final int NUMSLOT = 7;
private Command[] onCommands;
private Command[] offCommands;
private Command undoCommand;
public RemoteControl() {
onCommands = new Command[NUMSLOT];
offCommands = new Command[NUMSLOT];
for (int i=0; i< NUMSLOT; i++) {
onCommands[i] = new NoCommand();
offCommands[i] = new NoCommand();
}
undoCommand = new NoCommand();
}
public void setCommand (int slot,
Command onCommand, Command offCommand) {
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
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();
}
public String toString() {
StringBuilder descritption = new StringBuilder();
descritption.append("\n------ Remote Control -------\n");
for (int i = 0; i < NUMSLOT; i++) {
descritption.append("[slot " + i + "] " + onCommands[i].getClass().getSimpleName()
+ " " + offCommands[i].getClass().getSimpleName() + "\n");
}
return descritption.toString();
}
}
public class RemoteLoader {
public static void main(String[] args) {
Light light = new Light();
Stereo stereo = new Stereo();
RemoteControl remoteControl = new RemoteControl();
remoteControl.setCommand(0,
new LightOnCommand(light), new LightOffCommand(light));
remoteControl.setCommand(1, new StereoOnWithCDCommand(stereo),
new StereoOffWithCDCommand(stereo));
System.out.println(remoteControl);
remoteControl.onButtonWasPushed(0);
remoteControl.offButtonWasPushed(0);
remoteControl.undoButtonWasPushed();
}
}
Example - Runnable¶
public interface Runnable {
public abstract void run();
}
public interface Executor {
void execute(Runnable command);
}
class SerialExecutor implements Executor {
private final Queue<Runnable> tasks = new ArrayDeque<>();
private final Executor executor;
private Runnable active;
SerialExecutor(Executor executor) {
this.executor = executor;
}
public synchronized void execute(Runnable r) {
tasks.add(() -> {
try {
r.run();
} finally {
scheduleNext();
}
});
if (active == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((active = tasks.poll()) != null) {
executor.execute(active);
}
}
}