👉文章示例代码👈

定义

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化。

四个角色

命令模式主要有以下四个角色:

  • 抽象命令类Command:声明执行操作的接口。
  • 具体命令类Concrete Command:是抽象命令类的具体实现类,持有接受者对象,同时通过调用接收者的功能来完成命令要执行的操作。
  • 接收者Receiver:执行命令功能的相关操作。
  • 调用者Invoker:拥有很多命令对象,并通过访问命令对象来执行相关请求,其不直接访问接收者。

场景示例

笔者女朋友在一家知识付费公司做人事兼老板助理,常常会接收到一些来自老板的工作安排。

笔者这里以此为例。假设这天下班,女朋友接到老板的以下几个工作安排:

  • 明早9点准时在公司公号上发布一篇xx的推文。
  • 上午和老板一起外出看讲座场地。
  • 安排明天下午两点的会议。

创建抽象命令类

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @author zhh
* @description 抽象命令接口
* @date 2020-03-02 16:31
*/
public interface Command {

/**
* 执行命令
*/
void 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
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
/**
* @author zhh
* @description 发送推文命令
* @date 2020-03-02 16:33
*/
public class SendTweetsCommand implements Command {

private Staff staff;

public SendTweetsCommand(Staff staff) {
this.staff = staff;
}

public void execute() {
staff.sendTweets();
}
}


/**
* @author zhh
* @description 看场地命令
* @date 2020-03-02 16:37
*/
public class LookVenueCommand implements Command {

private Staff staff;

public LookVenueCommand(Staff staff) {
this.staff = staff;
}

public void execute() {
staff.lookVenue();
}
}


/**
* @author zhh
* @description 安排会议命令
* @date 2020-03-02 16:38
*/
public class AttendMeetingCommand implements Command {

private Staff staff;

public AttendMeetingCommand(Staff staff) {
this.staff = staff;
}

public void execute() {
staff.attendMeeting();
}
}

创建接受者

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
/**
* @author zhh
* @description 接受者类
* @date 2020-03-02 16:58
*/
public class Staff {

private String name;

public Staff(String name) {
this.name = name;
}

/**
* 发推文
*/
public void sendTweets() {
System.out.println(this.name + "早上9点准时在公司公号上发布一篇xx的推文");
}

/**
* 看场地
*/
public void lookVenue() {
System.out.println(this.name + "上午和老板一起外出看讲座场地");
}

/**
* 安排会议
*/
public void attendMeeting() {
System.out.println(this.name + "安排下午两点的会议");
}
}

创建调用者

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
/**
* @author zhh
* @description 调用者类
* @date 2020-03-02 16:43
*/
public class Boss {

private List<Command> commandList = new ArrayList<Command>();

/**
* 添加命令
* @param command 命令
*/
public void addCommand(Command command) {
commandList.add(command);
}

/**
* 发送命令
*/
public void sendCommands() {
for (Command command : commandList) {
command.execute();
}
commandList.clear();
}
}

测试类及输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* @author zhh
* @description 测试类
* @date 2020-03-02 16:48
*/
public class Test {

public static void main(String[] args) {
Staff staff = new Staff("亚萍");
Command sendTweetsCommand = new SendTweetsCommand(staff);
Command lookVenueCommand = new LookVenueCommand(staff);
Command attendMeetingCommand = new AttendMeetingCommand(staff);

Boss boss = new Boss();
boss.addCommand(sendTweetsCommand);
boss.addCommand(lookVenueCommand);
boss.addCommand(attendMeetingCommand);

boss.sendCommands();
}
}

测试类的输出结果如下:

亚萍早上9点准时在公司公号上发布一篇xx的推文
亚萍上午和老板一起外出看讲座场地
亚萍安排下午两点的会议

类结构图

以上示例类的结构图如下所示
image.png

总结

适用场景

  • 当请求调用者和请求接受者需要解耦时,命令模式使得调用者和接受者不直接交互。
  • 需要抽象出等待执行的行为。

优点

  • 降低系统的耦合度。
  • 良好的扩展性。新增或者删除命令不会影响其他类。

缺点

对于每一个具体的操作都需要对应设计一个具体的命令类,这会导致类的数目的增加,增加系统的复杂性。

参考