【设计模式】之命令模式(Command)
原创
©著作权归作者所有:来自51CTO博客作者Lyndon_梁飞的原创作品,请联系作者获取转载授权,否则将追究法律责任
命令模式的定义为:把一个请求封装成一个对象,因此可以使用不同的请求来参数化别的对象,将请求加入队列或者记录请求日志,并且支持撤销操作。
官方定义为: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();
}
}