现在我们手里有一副遥控器,上面有分别控制着电视、电灯、电脑开关的按钮,当我们按下按钮的开或者关控制键时,这些电器就会做出相应的反应,即请求者(遥控器),向接受者(电器)发送命令,接受者根据收到的命令做出相应的反应,这就是典型的命令模式场景,它利用命令这个接口实现了请求者与接受者的解耦。
命令模式
定义:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化对象,命令模式也支持撤销的操作。
UML图
- 请求者:发起命令的对象
- 命令接口:定义了execute方法,具体功能实现交由子类完成
- 具体命令:实现了不同的功能方法,并包含有一个接受者对象,使接受者对象执行同样的操作
- 接收者:知道如何实施与执行一个请求相关的操作
例子
首先,让我们先来建立一个命令接口
package command;
/**
* 命令接口
*/
public interface Command {
void execute();
}
以控制电灯开关的命令为例,各实现电灯的开/关 接口
package command;
/**
* 开电灯命令,实现了命令接口,并持有命令接受者变量
*/
public class LightOnCommand implements Command {
//私有化命令的接受者
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.lightOn();
}
}
package command;
public class LightOffCommand implements Command {
//私有化命令的接受者
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.lightOff();
}
}
命令实现类实现了命令接口,并持有命令的接受者,请求者调用命令时,命令会向接受者发起请求,这样请求者与接受者就实现了解耦。
最后来实现遥控器(invoker):
package command;
/**
* 遥控器
*/
public class RemoteControl {
Command[] onCommands = new Command[5];
Command[] offCommands = new Command[5];
public void setOnCommond(Command onCommond,int i) {
onCommands[i] = onCommond;
}
public void setOffCommand(Command offCommand,int i) {
offCommands[i] = offCommand;
}
public void onButtonExcute(int i){
onCommands[i].execute();
}
public void offButtonExcute(int i){
offCommands[i].execute();
}
}
这样,我们就可以调用遥控器的开关来控制相应电器的行为了,也可以设置遥控器的开关的种类。
小结
适用场景
- 命令的发送者和命令的接受者有不同的生命周期,命令发送了不是马上执行
- 命令有不同的管理逻辑
- 需要支持撤销/重做命令
所以,命令模式是对功能方法的抽象,而不是对对象的抽象,它将功能方法提升到对象角度来操作,便于我们实现解耦。
源码在这里:我的github地址