Design Patterns(十三) Command

Command pattern is a data driven design pattern and falls under behavioral pattern category. A request is wrapped under an object as command and passed to invoker object. Invoker object looks for the appropriate object which can handle this command and passes the command to the corresponding object which executes the command.

前言

    命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

命令模式

基本介绍:

1) 命令模式(Command Pattern):在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计;
2) 命名模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦;
3) 在命名模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求(即命名),同时命令模式也支持可撤销的操作;
4) 通俗易懂的理解:将军发布命令,士兵去执行。其中有几个角色:将军(命令发布者)、士兵(命令的具体执行者)、命令(连接将军和士兵)。Invoker是调用者(将军),Receiver是被调用者(士兵),MyCommand是命令,实现了Command接口,持有接收对象;

命令模式-UML图:


代码:

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
/**
* @Auther: Arsenal
* @Date: 2020-03-18 22:48
* @Description: 命令模式
*/
public class CommandDemo {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);
Command[] commands = new Command[1];
commands[0] = command;
Command macroCommand = new MacroCommand(commands);
Invoker invoker = new Invoker(macroCommand);
invoker.doInvokerAction();
}
}

/**
* 命令角色
*/
interface Command {
void execute();

void undo();
}

/**
* 具体命令角色
*/
class ConcreteCommand implements Command {

// 持有接收者的引用
private Receiver receiver;

public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}

@Override
public void execute() {
receiver.doAction();
}

@Override
public void undo() {
receiver.unDoAction();
}
}

/**
* 具体命令角色
*/
class MacroCommand implements Command {

Command[] commands;

public MacroCommand(Command[] commands) {
this.commands = commands;
}

@Override
public void execute() {
for (Command command : commands) {
command.execute();
}
}

@Override
public void undo() {
for (Command command : commands) {
command.undo();
}
}
}

/**
* 被调用者(士兵)
*/
class Receiver {
//接收者真正执行命令
public void doAction() {
System.out.println("doAction");
}

public void unDoAction() {
System.out.println("unDoAction");
}
}

/**
* 调用者(将军)
*/
class Invoker {
//持有命令对象的引用,将动作委托给命令对象执行
private Command command;

public Invoker(Command command) {
this.command = command;
}

public void doInvokerAction() {
command.execute();
}
}

总结

命令模式的注意事项和细节:

1) 将发起请求的对象与执行请求的对象解耦。发起请求的对象是调用者,调用者只要调用命令对象的execute()方法就可以让接收者工作,而不必知道具体的接收者对象是谁、是如何实现的,命令对象会负责让接收者执行请求的动作,也就是说:”请求发起者”和“请求执行者”之间的解耦是通过命令对象实现的,命令对象起到了纽带桥梁的作用;
2) 容易设计一个命令队列。只要把命令对象放到列队,就可以多线程的执行命令;
3) 容易实现对请求的撤销和重做;
4) 命令模式不足:可能导致某些系统有过多的具体命令类,增加了系统的复杂度,这点在在使用的时候要注意;
5) 空命令也是一种设计模式,它为我们省去了判空的操作。在上面的实例中,如果没有用空命令,我们每按下一个按键都要判空,这给我们编码带来一定的麻烦;
6) 命令模式经典的应用场景:界面的一个按钮都是一条命令、模拟CMD(DOS命令)订单的撤销/恢复、触发-反馈机制。

延伸

    命令模式
    命令模式-菜鸟教程
    Design Patterns - Command Pattern
    设计模式之命令模式(Command Pattern)
    尚硅谷Java设计模式,韩顺平图解java设计模式

Content
  1. 1. 前言
  2. 2. 命令模式
  3. 3. 总结
  4. 4. 延伸