命令模式(Command Pattern)
半塘 2024/3/29 Java进阶
将请求封装成一个对象,以便使用命令来参数化其它对象,或者将命令对象放入队列中进行排队,或者将命令对象的操作记录到日志中,以及支持可撤销的操作。
# 1、命令模式案例
一个文本对象,将各个方法请求封装成对象,将一个个命令对象放入队列中,通过执行者以命令的方式进行调用
public class TextContent {
private String content = "";
// 新增请求
public void addStr(String content){
this.content = content;
}
// 删除请求
public void delLastStr(){
if(!content.isEmpty()){
content = content.substring(0,content.length()-1);
}
}
public String getContent(){
return content;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
将方法请求封装成命令对象
public interface TextCommand {
void execute();
}
// 新增请求封装为命令对象
public class AddStrCommand implements TextCommand {
private TextContent textContent;
private String content;
public AddStrCommand(TextContent textContent,String content) {
this.textContent = textContent;
this.content = content;
}
@Override
public void execute() {
textContent.addStr(textContent.getContent()+content);
}
}
// 删除最后一个字符封装为命令对象
public class RemoveLastStrCommand implements TextCommand {
private TextContent textContent;
public RemoveLastStrCommand(TextContent textContent) {
this.textContent = textContent;
}
@Override
public void execute() {
textContent.delLastStr();
}
}
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
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
命令调用者,这里直接用队列封装
public class TextCommandInvoker {
private final Queue<TextCommand> commandQueue = new LinkedList<>();
public void addCommand(TextCommand command){
commandQueue.offer(command);
}
public void executionCommand(){
while (!commandQueue.isEmpty()){
commandQueue.poll().execute();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ClientTest {
public static void main(String[] args) {
// 影响结果的对象
TextContent textContent = new TextContent();
// 执行者
TextCommandInvoker invoker = new TextCommandInvoker();
// 将命令给执行者
invoker.addCommand(new AddStrCommand(textContent, "AAA;")); // AAA; 但没执行命令所以为空
invoker.addCommand(new AddStrCommand(textContent, "AAA;")); // AAA;AAA; 但没执行命令所以为空
System.out.println("textContent1: "+textContent.getContent());
// 将命令给执行者
invoker.addCommand(new RemoveLastStrCommand(textContent)); // AAA;AAA 但没执行命令所以为空
System.out.println("textContent2: "+textContent.getContent());
invoker.addCommand(new RemoveLastStrCommand(textContent)); // AAA;AA 但没执行命令所以为空
// 执行者统一执行命令
invoker.executionCommand(); // 执行命令:AAA;AA
System.out.println("textContent3: "+textContent.getContent());
}
}
/**
* 输出结果:
* textContent1:
* textContent2:
* textContent3: AAA;AA
* /
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
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
# 2、增加撤回功能
TextContent不用改,我们只需要在相应命令对象方法增加自己功能的撤回就行
public interface TextCommand {
void execute();
void undo();
}
1
2
3
4
5
2
3
4
5
public class AddStrCommand implements TextCommand {
private TextContent textContent;
// 记录增加的内容
private String content;
public AddStrCommand(TextContent textContent,String content) {
this.textContent = textContent;
this.content = content;
}
@Override
public void execute() {
textContent.addStr(textContent.getContent()+content);
}
@Override
public void undo() {
textContent.addStr(textContent.getContent().replaceFirst(content,""));
}
}
public class RemoveLastStrCommand implements TextCommand {
private TextContent textContent;
// 记录删除的内容
private String delStr;
public RemoveLastStrCommand(TextContent textContent) {
this.textContent = textContent;
}
@Override
public void execute() {
this.delStr = textContent.getContent().substring(textContent.getContent().length()-1);
textContent.delLastStr();
}
@Override
public void undo() {
textContent.addStr(textContent.getContent()+delStr);
}
}
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
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
public class TextCommandInvoker {
private final Queue<TextCommand> commandQueue = new LinkedList<>();
// 记录历史
private final Deque<TextCommand> historyDeque = new ArrayDeque<>();
public void addCommand(TextCommand command){
commandQueue.offer(command);
}
public void executionCommand(){
while (!commandQueue.isEmpty()){
TextCommand command = commandQueue.poll();
historyDeque.addLast(command);
command.execute();
}
}
public void undoCommand(){
if(!historyDeque.isEmpty()){
historyDeque.pollLast().undo();
}else {
System.out.println("没有可撤销操作");
}
}
}
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
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
public class ClientTest {
public static void main(String[] args) {
// 最终成果
TextContent textContent = new TextContent();
// 执行者
TextCommandInvoker invoker = new TextCommandInvoker();
// 将命令给执行者
invoker.addCommand(new AddStrCommand(textContent, "AAA;")); // AAA; 但没执行命令所以为空
invoker.addCommand(new AddStrCommand(textContent, "AAA;")); // AAA;AAA; 但没执行命令所以为空
System.out.println("textContent1: "+textContent.getContent());
// 将命令给执行者
invoker.addCommand(new RemoveLastStrCommand(textContent)); // AAA;AAA 但没执行命令所以为空
System.out.println("textContent2: "+textContent.getContent());
invoker.addCommand(new RemoveLastStrCommand(textContent)); // AAA;AA 但没执行命令所以为空
// 执行者统一执行命令
invoker.executionCommand(); // 执行命令:AAA;AA
System.out.println("textContent3: "+textContent.getContent());
// 撤销命令
invoker.undoCommand(); // 撤销一次:AAA;AA ===> AAA;AAA
System.out.println("textContent4: "+textContent.getContent());
invoker.undoCommand(); // 撤销第二次:AAA;AAA ===> AAA;AAA;
System.out.println("textContent5: "+textContent.getContent());
invoker.undoCommand(); // 撤销第三次:AAA;AAA; ===> AAA;
System.out.println("textContent6: "+textContent.getContent());
invoker.undoCommand();
invoker.undoCommand();
}
}
/**
* 输出结果:
* textContent1:
* textContent2:
* textContent3: AAA;AA
* textContent4: AAA;AAA
* textContent5: AAA;AAA;
* textContent6: AAA;
* 没有可撤销操作
* /
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
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