# 命令模式
本文作者:程序员飞云
# 1. 什么是命令模式?
命令模式(Command): 将一个请求分装成一个对象,从而可以使用不同的请求对客户进行参数化;对于请求排队或者请求日志,以及支持可撤销的操作。
主要是将客户端和执行请求的对象解耦。
举个常见的两个例子
一个是我们生活中使用遥控器来控制电视,我们控制遥控器(相当于客户端),点击遥控按钮*(命令)来控制电视( 执行请求的对象),即使遥控器坏了也没用影响,可以使用新的遥控器,但是电视坏了,遥控器就没用了。
另一个是去烧烤店点单,我们告诉服务员,通过点单命令来告诉烧烤师傅 要考什么肉,而这个服务员是谁我们不关心,这个服务员忙,我们可以找另一个服务员。( 这个例子不大适合小的烧烤店,一般老板一个人就包了2个人的工作)
# 2. 优点
- 可以容易设计一个命令队列
- 容易的将一些命令写入日志
- 允许接收请求的一方决定是否拒绝请求
- 容易实现对请求的撤销和重做
- 加入了新的命令类不影响其他的类 6解耦了请求者以及接收者,系统更加灵活
# 3. 使用场景
- 操作多种的复杂操作,比如排队,请求日志,记录操作,撤消重做等等
- 系统需要增加新的命令不影响之前的功能,或者处理复杂的组合命令
# 4. 案例一:遥控器--电视
# 1. 接受者: 电视
最终执行命令的对象,知道具体的相关操作
这里就设置一个电视的电视名字字段,有两个功能开启电视,关闭电视
/**
* 接收者,电视设备
*/
public class Device {
private String name;
public Device(String name) {
this.name = name;
}
public void on() {
System.out.println("开启: " + this.name);
}
public void off() {
System.out.println("关闭: " + this.name);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 2. 命令Command
相当于总的遥控器按钮制定的规范,这个命令才是控制电视开关的核心
public interface Command {
void execute(); // 执行命令
}
1
2
3
2
3
# 3. 开启按钮的命令
/**
* 开启命令
*/
public class TurnOnCommand implements Command {
private Device device;
public TurnOnCommand(Device device) {
this.device = device;
}
@Override
public void execute() {
device.on();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 4. 关闭按钮的命令
/**
* 关闭命令
*/
public class TurnOffCommand implements Command {
private Device device;
public TurnOffCommand(Device device) {
this.device = device;
}
@Override
public void execute() {
device.off();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 5. 调用者
遥控器点击按钮后,如果是开,就是执行的TurnOnCommand命令,然后命令执行里面的execute
/**
* 遥控器
*/
public class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command=command;
}
/**
* 按下按钮
*/
public void buttonWasPressed() {
command.execute();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 6. 客户端
用户操作,点击遥控器
需要对应的电视,按钮,操作。
public class Client {
public static void main(String[] args) {
// 电视
Device device = new Device("TCL");
// 遥控器
RemoteControl remoteControl = new RemoteControl();
// 对电视发布命令
TurnOnCommand turnOnCommand = new TurnOnCommand(device);
// 执行命令
remoteControl.setCommand(turnOnCommand);
// 响应结果
remoteControl.buttonWasPressed();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 7. 进阶 :记录历史
这个操作其实还算简单,就是使用一个集合来存放对应的命令
/**
* 遥控器
*/
public class RemoteControl {
private Command command;
private List<Command> commands = new ArrayList<>();
public void setCommand(Command command) {
this.commands.add(command);
this.command = command;
}
/**
* 按下按钮
*/
public void buttonWasPressed() {
command.execute();
}
public void buttonHistory() {
for (Command command : commands) {
command.execute();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 8. 进阶:显示一系列操作
public class Client {
public static void main(String[] args) {
// 电视
Device device = new Device("TCL");
// 遥控器
RemoteControl remoteControl = new RemoteControl();
// 对电视发布命令
TurnOnCommand turnOnCommand = new TurnOnCommand(device);
TurnOffCommand turnOffCommand = new TurnOffCommand(device);
TurnOnCommand turnOnCommand2 = new TurnOnCommand(device);
// 执行命令
remoteControl.setCommand(turnOnCommand);
remoteControl.setCommand(turnOffCommand);
remoteControl.setCommand(turnOnCommand2);
// 响应结果
remoteControl.buttonWasPressed();
System.out.println("------------");
// 操作历史
remoteControl.buttonHistory();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 9. 运行截图
# 10. uml图
# 5. 案例二:烤肉串师傅—服务员
# 1. 接收者: 烤肉串师傅
具有考鸡翅和考羊肉的功能
/**
* 烤肉师傅
*/
public class Barbecuer {
public void bakeMutton() {
System.out.println("烤羊肉串");
}
public void bakeChickenWing() {
System.out.println("烤鸡翅");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 2. 命令Command
执行命令
public interface Command {
void execute(); // 执行命令
}
1
2
3
2
3
# 3. 具体命令
烤羊肉命令
/**
* 烤羊肉命令
*/
public class BakeMuttonCommand implements Command {
private Barbecuer barbecuer;
public BakeMuttonCommand(Barbecuer barbecuer) {
this.barbecuer = barbecuer;
}
@Override
public void execute() {
barbecuer.bakeMutton();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
烤鸡翅命令
/**
* 烤鸡翅命令
*/
public class BakeChickenWingCommand implements Command {
private Barbecuer barbecuer;
public BakeChickenWingCommand(Barbecuer barbecuer) {
this.barbecuer = barbecuer;
}
@Override
public void execute() {
barbecuer.bakeChickenWing();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 4. 调用者–服务员
服务员发送相关的命令
/**
* 服务员
*/
public class Waiter {
//持有命令对象
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void action() {
command.execute();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 5. 客户端–用户
public class Client {
public static void main(String[] args) {
// 烤肉师傅
Barbecuer barbecuer = new Barbecuer();
// 服务员
Waiter waiter = new Waiter();
// 点菜命令
BakeChickenWingCommand bakeChickenWingCommand = new BakeChickenWingCommand(barbecuer);
// 服务员接受命令
waiter.setCommand(bakeChickenWingCommand);
// 反馈
waiter.action();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
如果想要实现记录历史可以仿照前面的,还可以实现移除订单等等相关操作。