设计模式笔记 - 命令模式(Command Pattern)

模式定义

命令模式(Command Pattern)将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,又称事务(Transaction)模式。


模式结构

命令模式包含如下角色:

  • Command:抽象命令类
  • ConcreteCommand:具体命令类
  • Invoker:调用者
  • Receiver:接受者
  • Client:客户类

img


模式实例

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
/*
* 此例为电视机遥控器。其中电视机是请求的接受者,遥控器是请求的发送者,遥
* 控器上有一些按钮,不同的按钮对应电视机的不同的操作。抽象命令角色有一个
* 命令接口来扮演,有三个具体的命令类实现了该抽象命令接口:打开电视机、关
* 闭电视机、切换频道。
*/
// Command - 抽象命令类
public interface Command {
public void execute();
}

// ConcreteCommand - 具体命令类 - 篇幅问题只实现前两个
// 打开电视机
public class TVOpenCommand implements Command {
private Televition tv;

public TVOpenCommand(Televition tv) {
this.tv = tv;
}

public void execute () {
this.tv.open();
}
}

// 关闭电视机
public class TVCloseCommand implements Command {
private Televition tv;

public TVCloseCommand(Televition tv) {
this.tv = tv;
}

public void execute() {
this.tv.close();
}
}

// 空命令 - 利用空命令取代null确保运行时的安全
public class NoCommand implements Command {
public void execute() {
System.out.println("No command here");
}
}

// Invoker - 调用者
public class Controller {
private Command[] commands;
private static final int length = 7;

public Controller() {
commands = new Command[length];
for (int i = 0; i < length; i++) {
commands[i] = new NoCommand();
}
}

public setCommand(int index, Command command) {
commands[index] = command;
}

public void pushButton(int index) {
commands[index].execute();
}
}

// Receiver - 接受者
public class Television {
public Television() {
;
}

public void on() {
System.out.println("Television is on now!");
}

public void off() {
System.out.println("Television is off now!");
}
}

// Client - 客户类
public class Client {
public static void main(String[] args) {
Television tv = new Television();
TVOpenCommand tvOpen = new TVOpenCommand(tv);
TVCloseCommand tvClose = new TVOCloseCommand(tv);

Controller controller = new Controller();
controller.setCommand(0, tvOpen);
controller.setCommand(1, tvClose);

controller.pushButton(0);
controller.pushButton(1);
}
}

模式分析

命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开。请求的一方发出请求,要求执行一个操作;接受的一方收到请求,并执行操作。

  • 命令模式允许请求的一方和接受一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。
  • 命令模式将请求本身封装称为一个对象,使得该请求可以像其他对象一样被存储或传递。
  • 命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接受者相关联。

命令模式的优点:

  • 发送者与接受者分别负责命令的发送与处理,将彼此的责任分离,降低系统的耦合度,易于系统的扩展。
  • 较容易设计出命令队列和宏命令(组合若干条命令)
  • 较容易设计出撤销操作和恢复操作(利用栈存储已操作的命令)

命令模式的缺点:

  • 使用命令模式可能会导致某些系统有过多的具体命令类。因为针对于每一个命令都需要设计一个具体命令类(开与关等..),在一定程度上难以管理和维护所有的命令。


参考资料:

[1] https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/command.html