命令模式的定义为:把一个请求封装成一个对象,因此可以使用不同的请求来参数化别的对象,将请求加入队列或者记录请求日志,并且支持撤销操作。
官方定义为:The Command Pattern encapsulates a request as an object, thereby letting you parameterize other objects with different request, queue or log requests, and support undoable operations.


Command中比较重要的几个参与者:
Command
- declares an interface for executing an operation.
ConcreteCommand 
- defines a binding between a Receiver object and an action
- implements Execute by invoking the corresponding operation(s) on Receiver.
Client
- Create a ConcreteCommand ojbect and sets its receiver.
Invoker
- asks the command to carry out the request.
Receiver
- konws how to perform the oprations associated with carrying out a request, Any class may serve as a Receiver.




Command模式将命令的发送者与接受者分离,Command对象即为两者间的桥梁。
首先必须定义一个命令的接口(Command),接口中定义命令所支持的操作,然后定义具体的命令类(ConcreteCommand),并指定命令的接收着(Receiver),有时候接收者与命令可以合二为一。
利用多态机制,调用者(Invoker)只需要定义命令的接口(Command)对象便可,命令的细节对调用着是透明的。


还有一个比较重要的特点就是undoable,
undo的过程就是Execute的逆过程,比较负责的撤销动作则用到了Memento模式。


命令对象不一定只是一个单一的命令,也可以是很多命令的集合,这样命令就可以不用定义Invoker。

《Header First Design Patterns》中的示例代码如下:

public interface Command {
public void execute();
public void undo();
}

public class CeilingFanCommand implements Command {
protected CeilingFan ceilingFan;
protected int prevSpeed;

public CeilingFanCommand(CeilingFan ceilingFan) {
this.ceilingFan = ceilingFan;
}

public void execute() {
prevSpeed = ceilingFan.getSpeed();
}

public void undo() {
if (prevSpeed == CeilingFan.HIGH) {
ceilingFan.high();
} else if (prevSpeed == CeilingFan.MEDIUM) {
ceilingFan.medium();
} else if (prevSpeed == CeilingFan.LOW) {
ceilingFan.low();
} else if (prevSpeed == CeilingFan.OFF) {
ceilingFan.off();
}
}
}
public class CeilingFanHighCommand extends CeilingFanCommand {
public CeilingFanHighCommand(CeilingFan ceilingFan) {
super(ceilingFan);
}

@Override
public void execute() {
super.execute();
ceilingFan.high();
}
}
public class CeilingFanMediumCommand extends CeilingFanCommand {
public CeilingFanMediumCommand(CeilingFan ceilingFan) {
super(ceilingFan);
}

@Override
public void execute() {
super.execute();
ceilingFan.medium();
}
}

public class CeilingFanOffCommand extends CeilingFanCommand {
public CeilingFanOffCommand(CeilingFan ceilingFan) {
super(ceilingFan);
}

@Override
public void execute() {
super.execute();
ceilingFan.low();
}
}

public class NoCommand implements Command {
public NoCommand() { }

@Override
public void execute() { }

@Override
public void undo() { }
}

public class CeilingFan {
public static final int HIGH = 3;
public static final int MEDIUM = 2;
public static final int LOW = 1;
public static final int OFF = 0;
String location;
int speed;

public CeilingFan(String location) {
this.location = location;
speed = OFF;
}

public void high() {
speed = HIGH;
}

public void medium() {
speed = MEDIUM;
}

public void low() {
speed = LOW;
}

public void off() {
speed = OFF;
}

public int getSpeed() {
return speed;
}
}

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;
}

public void onButtonWasPressed(int slot) {
onCommands[slot].execute();
undoCommand = onCommands[slot];
}

public void offButtonWasPressed(int slot) {
offCommands[slot].execute();
undoCommand = offCommands[slot];
}

public void undoButtonWasPressed() {
undoCommand.undo();
}

public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("\n------ Remote Control ------\n");
for (int i = 0; i < onCommands.length; i++) {
sb.append("[slot " + i + "] " + onCommands[i].getClass().getName() + " " + offCommands[i].getClass().getName() + "\n");
}
return sb.toString();
}
}

public class RemoteLoader {
public static void main(String[] args) {
RemoteControlWithUndo remoteControl = new RemoteControlWithUndo();

CeilingFan ceilingFan = new CeilingFan("Living Room");

CeilingFanMediumCommand ceilingFanMedium =
new CeilingFanMediumCommand(ceilingFan);
CeilingFanHighCommand ceilingFanHigh =
new CeilingFanHighCommand(ceilingFan);
CeilingFanOffCommand ceilingFanOff =
new CeilingFanOffCommand(ceilingFan);

remoteControl.setCommand(0, ceilingFanMedium, ceilingFanOff);
remoteControl.setCommand(1, ceilingFanHigh, ceilingFanOff);

remoteControl.onButtonWasPressed(0);
remoteControl.offButtonWasPressed(0);
System.out.println(remoteControl);
remoteControl.undoButtonWasPressed();

remoteControl.onButtonWasPressed(1);
System.out.println(remoteControl);
remoteControl.undoButtonWasPressed();
}
}