设计模式(8)——命令模式

本文介绍命令模式的概念和应用。

基本思想和原则

将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。

动机

为了使客户类在不需要了解具体细节的情况下获得想要的结果,我们将一个个命令封装成对象,即命令对象,由一个调度者来使命令对象得以执行。

实现

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
public class ProductManager {
public void makeRequirements() {
System.out.println("ProductManager make requirements.");
}
}

public class Designer {
public void design() {
System.out.println("Designer desgin.");
}
}


public class Programer {
public void writeCode() {
System.out.println("Programer write code.");
}
}

public abstract class Command {
protected ProductManager productManager = new ProductManager();
protected Designer designer = new Designer();
protected Programer programer = new Programer();
public abstract void execute();
}

public class FunACommand extends Command {
@Override
public void execute() {
this.programer.writeCode();
}
}

public class FunBCommand extends Command{
@Override
public void execute() {
this.productManager.makeRequirements();
this.designer.design();
this.programer.writeCode();
}
}

public class ProjectManager {
private Command command;

public void setCommand(Command command) {
this.command = command;
}

public void action() {
this.command.execute();
}
}

public class Test {
public static void main(String[] args) {
ProjectManager projectManager = new ProjectManager();

Command command1 = new FunACommand();
projectManager.setCommand(command1);
projectManager.action();
}
}

输出如下:

1
Programer write code.

如果现在想执行FunBCommand,只需要将调用端改为:

1
2
3
4
5
6
7
8
9
10
public class Test {
public static void main(String[] args) {
ProjectManager projectManager = new ProjectManager();

// Command command1 = new FunACommand();
Command command2 = new FunACommand();
projectManager.setCommand(command2);
projectManager.action();
}
}

输出如下:

1
2
3
ProductManager make requirements.
Designer desgin.
Programer write code.

上面的代码场景中有四个角色:产品经理、设计师、程序员和项目经理,其中项目经理作为一个调度者,负责向下传递命令给产品经理、设计师和程序员。我们将具体的命令封装成命令对象,客户类只需要实例化具体的命令对象,然后传递给项目经理,就能执行相应的命令。具体到上面的例子,FunACommandFunBCommand分别封装了两个命令,其中FunACommand只需要程序员参与,FunBCommand则需要产品经理、设计师和程序员的共同参与。如果有新的命令,可以继续用这种模式封装起来。

优点

将调用者和具体执行任务的类之间解耦,调用者不需要了解具体执行任务的类,只需要知道命令即可。命令模式的可扩展性也很好,当需要增加新的命令时,增加具体命令的类即可完成扩展。

缺点

当具体的命令非常多的情况下,会造成整个Command类体系非常庞大。