行为型设计模式的一种,将行为的请求者和行为的处理者分开。

【DP】定义

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

使用场景

当行为的请求者和行为的处理者耦合度太高的时候,需要考虑使用命令模式,将行为以命令类的形式抽离出来,从而将请求者和处理者解耦。

类图

命令模式

类图核心: 1. “命令”依赖“行为处理者”, 即命令的定义不依赖具体处理命令的人,同一个命令可以由不同处理命令的人处理,将命令和执行人抽象分开;

  1. 通过命令接口将行为请求者和行为处理者分开,让请求者只做记录有哪些命令执行的事儿,让处理者只包含处理具体命令的代码,做到二者职责分离并保证职责单一。

抽离出来的命令类并不真正的执行命令,抽离出来是为了让请求者更好的记录,保证多个命令能够排队、记录或撤销。

举例

当在客户端设计一张报表时,会有很多命令,如设置显示区域、设置排序字段、设置字体等,同时还有一种非功能性功能:撤销与恢复。

在操作报表时的各种命令可以放在一个列表中,当撤销时从列表中移除组后一个元素即可。

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/**
* 行为处理者
*/
public class Executor {
public void setFontSize() {
// do something
}
public void undoSetFontSize() {
// do something
}
public void setOrder() {
// do something
}
public void undoSetOrder() {
// do something
}
}

/**
* 命令抽象类
*/
public abstract class Command {

/**
* 执行人
*/
Executor executor;

public Command(Executor executor) {
this.executor = executor;
}

/**
* 执行该命令
*/
void execute();

/**
* 撤销时应该做的事
*/
void fireUndo();
}

/**
* 设置字体大小命令
*/
public class SetFontSizeCommand extends Command {
public SetFontSizeCommand(Executor executor) {
super(executor);
}

@Override
public void execute() {
this.executor.setFontSize();
}

@Override
public void fireUndo() {
this.executor.undoSetFontSize();
}
}

/**
* 设置排序命令
*/
public class SetOrderCommand extends Command {
public SetOrderCommand(Executor executor) {
super(executor);
}

@Override
public void execute() {
this.executor.setOrder();
}

@Override
public void fireUndo() {
this.executor.undoSetOrder();
}
}

/**
* 操作记录
*/
public class OperateRecord {
// 命令列表
List<Command> commands = new LinkedList<>();

/**
* 增加命令
*/
public void addCommand(Command command) {
commands.add(command);
// 最多撤销20步,超过则去掉最先加入列表的命令
if (commands.size() > 20) {
commands.remove(0);
}
}

/**
* 执行命令
*/
public void execute() {
for (Command com : commands) {
com.execute();
}
}

// 撤销
public void undo() {
if (commands.size() == 0) {
return;
}
ICommand command = commands.get(commands.size() - 1);
// 移除最后一个命令
commands.remove(command);
// 触发移除命令的效果
command.fireUndo();
}
}

注意事项

再次重申该模式的两个重点:

  1. 行为请求者只记录命令,并不执行;
  2. 将命令与行为处理者分开,命令中指定行为处理者是谁,行为请求者只记录命令,而不记录具体处理者。