命令模式

介绍

将一系列的方法调用封装,用户只需要执行一个方法,那么所有被封装的方法都会按个执行调用。

使用场景

  • 需要抽象出待执行的动作,然后以参数的形式提供出来,类似于过程设计中的回调机制,而命令模式正式回调机制的一个面向对象的替代品。

  • 需要支持取消操作

  • 支持修改日志功能,这样当系统崩溃的时候,这些修改可以被重做一遍。

  • 需要支持事务操作。

简单实现

俄罗斯方块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class TerisMachine {

public void toLeft(){

System.out.println("向左移动");

}
public void toRight(){

System.out.println("向右移动");

}
public void fastToBottom(){

System.out.println("加速移动");
}
public void transform(){

System.out.println("改变形状");

}

}
1
2
3
4
public interface Command {

void execute();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public class LeftCommand implements Command{

private TerisMachine terisMachine;

public LeftCommand(TerisMachine terisMachine) {
this.terisMachine = terisMachine;
}

@Override
public void execute() {
this.terisMachine.toLeft();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public class RightCommand implements Command{

private TerisMachine terisMachine;

public RightCommand(TerisMachine terisMachine) {
this.terisMachine = terisMachine;
}

@Override
public void execute() {
this.terisMachine.toRight();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public class FallCommand implements Command{

private TerisMachine terisMachine;

public FallCommand(TerisMachine terisMachine) {
this.terisMachine = terisMachine;
}

@Override
public void execute() {
this.terisMachine.fastToBottom();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public class TransformCommand implements Command{

private TerisMachine terisMachine;

public TransformCommand(TerisMachine terisMachine) {
this.terisMachine = terisMachine;
}

@Override
public void execute() {
this.terisMachine.transform();
}
}
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
public class Buttons {

private LeftCommand leftCommand;
private RightCommand rightCommand;
private FallCommand fallCommand;
private TransformCommand transformCommand;

public void setLeftCommand(LeftCommand leftCommand) {
this.leftCommand = leftCommand;
}

public void setRightCommand(RightCommand rightCommand) {
this.rightCommand = rightCommand;
}

public void setFallCommand(FallCommand fallCommand) {
this.fallCommand = fallCommand;
}

public void setTransformCommand(TransformCommand transformCommand) {
this.transformCommand = transformCommand;
}

public void toLeft(){
leftCommand.execute();
}
public void toRight(){
rightCommand.execute();
}
public void fall(){
fallCommand.execute();
}
public void transform(){
transformCommand.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
27
public class Player {

public static void main(String[] args){

TerisMachine terisMachine = new TerisMachine();

LeftCommand leftCommand = new LeftCommand(terisMachine);
RightCommand rightCommand = new RightCommand(terisMachine);
FallCommand fallCommand = new FallCommand(terisMachine);
TransformCommand transformCommand = new TransformCommand(terisMachine);


Buttons buttons = new Buttons();
buttons.setLeftCommand(leftCommand);
buttons.setRightCommand(rightCommand);
buttons.setFallCommand(fallCommand);
buttons.setTransformCommand(transformCommand);

buttons.toLeft();
buttons.toRight();
buttons.fall();
buttons.transform();


}

}

对于这么简单的逻辑搞得这么复杂,这是为什么?也许大家更能接受的是下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Player {

public static void main(String[] args){

TerisMachine terisMachine = new TerisMachine();

terisMachine.toLeft();
terisMachine.toRight();
terisMachine.fastToBottom();
terisMachine.transform();


}

}

这样做开发起开很方便,每次我们增加或者修改游戏功能只需要修改TerisMachine类就可以了,然后对应的修改一下Player类,一切很方便,但是对于这样的逻辑,给以后负责维护的这些代码的人带来了麻烦。这违背了开闭原则。

除此之外,使用命令模式的另一个好处是可以实现命令记录功能,如上例中,我们在你请求这Buttons里使用一个数据结构来存储执行过的命令对象,以此可以方便的知道刚刚执行过哪些命令动作,并可以在需要时候恢复。

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器