【设计模式】之命令模式(Command)
命令模式的定义为:把一个请求封装成一个对象,因此可以使用不同的请求来参数化别的对象,将请求加入队列或者记录请求日志,并且支持撤销操作。
官方定义为: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(); }}