- 命令模式(封装调用)
定义
命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
优缺点
应用场景
web服务器的队列请求,以及应用的日志请求 。
例子
命令模式可将“动作的请求者”从“动作的执行者”对象中解耦。
客户负责创建命令对象。
public class Client{
public Command createCommandObject(){}
}
接收者和动作在命令对象中被绑在一起。命令对象包含了接收者上的一组动作。
public class Receiver{
public void action1(){}
public void action1(){}
}
命令对象(Command)提供了一个方法execute()。这个方法封装了一些动作,调用这个方法就会调用接收者的这些动作。
public class OneCommand implements Command{
@Override
public void execute() {
receiver.action1();
receiver.action2();
}
}
客户在调用者对象上调用setCommand()方法,并传入命令对象。
public class Invoker{
public Object setCommand(){}
}
未来的某个时间点,调用者将调用命令对象(Command)的execute()方法。这导致接收者(Receiver)的动作被调用。
接下来我们看看具体的例子:
家电自动化API的设计
实现命令接口:
public interface Command {
public void execute();
}
实现一个打开电灯的命令。Light类有两个方法:on()和off()。
public class LightOnCommand implements Command{
Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.on();
}
}
使用命令对象
public class SimpleRemoteControl {
Command slot;
public SimpleRemoteControl() {}
public void setCommand(Command command) {
slot = command;
}
public void buttonWasPressed() {
slot.execute();
}
}
public class RemoteControlTest {
public static void main(String[] args) {
SimpleRemoteControl remote = new SimpleRemoteControl();//调用者
Light light = new Light();//请求的接收者
//创建一个命令,将接收者传给它
LightOnCommand lightOn = new LightOnCommand(light);
remote.setCommand(lightOn);//把命令传给调用者
remote.buttonWasPressed();
}
}
实现遥控器
调用者类
public class RemoteControl {
Command[] onCommands;
Command[] offCommands;
public RemoteControl() {
onCommands = new Command[7];
offCommands = new Command[7];
Command noCommand = new NoCommond();
for(int i = 0; i < 7; i++) {
onCommands[i] = noCommand;
offCommands[i] = noCommand;
}
}
public void setCommand(int slot, Command onCommand, Command offCommand) {
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
public void onButtonWasPressed(int slot) {
onCommands[slot].execute();
}
public void offButtonWasPressed(int slot) {
offCommands[slot].execute();
}
}
命令类
public class LightOffCommand implements Command {
Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.off();
}
}
测试
public class RemoteLoader {
public static void main(String[] args) {
RemoteControl remoteControl = new RemoteControl();
Light livingRoomLight = new Light("livingRoomLight");
Light kitchenLight = new Light("kitchenLight");
LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight);
LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight)
LightOnCommand kitchenLightOn = new LightOnCommand(kitchenLight);
LightOffCommand kitchenLightOff = new LightOffCommand(kitchenLight);
remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);
remoteControl.setCommand(1, kitchenLightOn, kitchenLightOff);
remoteControl.onButtonWasPressed(0);
remoteControl.offButtonWasPressed(0);
remoteControl.onButtonWasPressed(1);
remoteControl.offButtonWasPressed(1);
}
}
撤销
public interface Command {
public void execute();
public void undo();
}
具体实现就不赘述了,基本同execute()。
设计原则
封装变化
多用组合,少用继承
针对接口编程,不针对实现编程
为交互对象之间松耦合设计而努力
类应该对扩展开放,对修改关闭
依赖抽象,不依赖具体类
总结
命令模式将发出请求的对象与执行请求的对象解耦;两者之间是通过命令对象沟通的 ;命令可以支持撤销,做法是实现一个undo()方法来回到execute()被执行前的状态。宏命令是命令的一种简单的延伸,允许调用多个命令;并也可支持撤销。命令可以用来实现队列请求、日志和事物系统。
小知识