定义
命令模式将"请求"封装成对象,以便使用不同的请求、队列或者日志来参数化其它对象。命令模式也支持可撤销的操作。
命令模式设计图
模式的意义
命令模式,主要的是将请求对象和执行对象进行解耦,也就是类图里面的Invoker和Receiver,这个模式主切入的点很小,但是应用很广,也是解耦思想一个比较重要的模式。
// 命令接口
public interface Command {
void execute();
void undo();
}
// 开灯功能
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.on();
}
public void undo() {
light.off();
}
// 关灯命令
public class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
public void execute() {
light.off();
}
public void undo() {
light.on();
}
}
public class RemoteInvoker {
/**
* 开关命令数组,模拟有很多对开关数组
*/
private Command[] onCommands;
private Command[] offCommands;
private Command undoCommand;
public RemoteInvoker(int length) {
// 有几组开关,就设置多少数组
onCommands = new Command[length];
offCommands = new Command[length];
// 把每个命令初始化成空命令,避免空指针异常
Command noCommand = new NoCommand();
undoCommand = noCommand;
for (int i = 0; i < length; i++) {
onCommands[i] = noCommand;
offCommands[i] = noCommand;
}
}
public void setCommond(int slot, Command onCommand, Command offCommand) {
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
public void onButton(int slot) {
onCommands[slot].execute();
undoCommand = onCommands[slot];
}
public void offButton(int slot) {
offCommands[slot].execute();
undoCommand = offCommands[slot];
}
public void undoButton() {
undoCommand.undo();
}
}
客户端
public class RemoteClient {
public static void main(String[] args) {
// 1、创建接收者
Light light = new Light();
// 2、创建命令对象
LightOnCommand lightOnCommand = new LightOnCommand(light);
LightOffCommand lightOffCommand = new LightOffCommand(light);
// 3、创建一组开关并用命令对象装载它
RemoteInvoker invoker = new RemoteInvoker(1);
invoker.setCommond(0, lightOnCommand, lightOffCommand);
// 4、测试
invoker.onButton(0);
invoker.offButton(0);
invoker.undoButton();
}
}
队列
命令可以将运算打包,放入一个我们设置的工作队列里面,一端负责添加命令,然后另一端则是线程,线程从队列中取出一个命令,调用他的execute()方法,等待这个调用完成,然后将此命令对象丢弃,再取出下一个命令。我们之前用Redis设计抢红包的时候,就是将用户抢到的红包对象放到队列里面,然后由线程循环的将这个对象消耗掉,虽然没有利用命令继承,但也是这种概念的简化版。