基本概念
命令模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦。
在命令模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求,同时命令模式也支持可撤销的操作。
通俗易懂的理解:将军发布命令,士兵去执行。其中有几个角色:将军(命令发布者)、士兵(命令的具体执行者)、命令(连接将军和士兵)。
命令模式的原理类图:
- Invoker:调用者角色;
- Command:命令角色,需要执行的所有命令都在这里,可以是接口或抽象类;
- Receiver:接收者角色,知道如何实施和执行一个请求相关的操
- ConcreteCommand:将一个接受者对象与一个动作绑定,调用接收者相应的的操作,实现execute。
那么这里举一个例子,酒店常常会有这么一个过程
具体的角色图示如下:
那么我们可以将图中每个角色,每个方法给与角色
- takerOrder就是传递命令的,在这里就是顾客将菜单传递给了女招待
- 顾客就是Client,这个很容易想到
- 订单就是command,因为command中包含所作所有命令,那么这里可以理解为厨师要做的所有的菜
- orderUp就是excute方法,这里就是女招待调用orderUp方法,做command里面的菜,而做菜的细节则交给厨师,所以女招待就是调用者,厨师就是接收者
下面用智能家居写代码示例:
Command角色
package com.lin.command;
public interface Command {
// 执行
void execute();
// 撤销
void undo();
}
在上面只是用了一个Command类,而这里写了两个实现,一个是关闭,一个是开启,为的是以后能够扩展命令,扩展了命令之后,当然,本身一个按钮也是一个对象,首要也是因为写的时候要写成一个对象,而扩展的时候命令可以扩展,但是后面可以明显看出,reciver不能扩展方法,所以如果reciver要扩展,那么需要另想办法。
package com.lin.command;
public class LightOffCommand implements Command{
LightReceiver lightReceiver = null;
@Override
public void execute() {
lightReceiver.off();
}
@Override
public void undo() {
lightReceiver.on();
}
public LightOffCommand(LightReceiver lightReceiver) {
this.lightReceiver = lightReceiver;
}
}
package com.lin.command;
public class LightOnCommand implements Command{
LightReceiver lightReceiver = null;
@Override
public void execute() {
lightReceiver.on();
}
@Override
public void undo() {
lightReceiver.off();
}
public LightOnCommand(LightReceiver lightReceiver) {
this.lightReceiver = lightReceiver;
}
}
那么如果没有命令的时候我们可以去用if去判断他是否为空再去执行,但是这里可以用类似于状态模式的方法,用无状态类先赋值给每个按钮,然后他里面的执行方法可以什么都不写,反正调用了也相当于什么也没有调用,这样就省去了if代码,有利于扩展性。
package com.lin.command;
// 控执行,初始化每个按钮
public class NoCommand implements Command{
@Override
public void execute() {
// TODO Auto-generated method stub
}
@Override
public void undo() {
// TODO Auto-generated method stub
}
}
这里就是接受命令的类了也就是厨师
package com.lin.command;
public class LightReceiver {
public void on() {
System.out.println("电灯打开了。");
}
public void off() {
System.out.println("电灯关闭了。");
}
}
这就是女招待,调用者,setCommand就是绑定的方法
package com.lin.command;
public class RemoteController {
Command[] onCommands;
Command[] offCommands;
Command undoCommand;
public RemoteController() {
onCommands = new Command[5];
offCommands = new Command[5];
for (int i = 0; i < offCommands.length; i++) {
onCommands[i] = new NoCommand();
offCommands[i] = new NoCommand();
}
}
public void setCommand(int no, Command onCommand, Command offCommand) {
onCommands[no] = onCommand;
offCommands[no] = offCommand;
}
// 按下开按钮
public void onButtonWasPushed(int no) {
onCommands[no].execute();
undoCommand = onCommands[no];
}
// 按下关按钮
public void offButtonWasPushed(int no) {
offCommands[no].execute();
undoCommand = offCommands[no];
}
// 按下撤销按钮
public void undoButtonWasPushed(int no) {
undoCommand.undo();
}
}
package com.lin.command;
public class Client {
public static void main(String[] args) {
LightReceiver lightReceiver = new LightReceiver();
LightOnCommand lightOnCommand = new LightOnCommand(lightReceiver);
LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver);
RemoteController remoteController = new RemoteController();
remoteController.setCommand(0, lightOnCommand, lightOffCommand);
System.out.println("=============按下开=============");
remoteController.onButtonWasPushed(0);
System.out.println("=============按下关=============");
remoteController.offButtonWasPushed(0);
System.out.println("=============按下撤销=============");
remoteController.undoButtonWasPushed(0);
}
}