Hexo

点滴积累 豁达处之

0%

19 命令模式

​  在软件开发中,我们经常需要向某些对象发送请求(调用其中的某个或某些方法),但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,此时,我们特别希望能够以一种松耦合的方式来设计软件,使得请求发送者与请求接收者能够消除彼此之间的耦合,让对象之间的调用关系更加灵活,可以灵活地指定请求接收者以及被请求的操作。命令模式为此类问题提供了一个较为完美的解决方案。

命令模式

1 概述

​  将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。命令模式通过这种封装的方式实现将客户端和接收端解耦。

命令模式的几个角色:

  1. 抽象命令接口Command:
1
定义命令的接口,声明执行的方法。
  1. 具体的命令对象ConcreteCommand:
1
持有具体的接受者对象,完成具体的具体的命令。
  1. 接受者对象Receiver:
1
接受者对象,真正执行命令的对象。
  1. 传递命令对象Invoker:
1
持有命令对象,要求命令对象执行请求。
  1. 客户端对象Client:
1
创建具体命令的对象并且设置命令对象的接受者。

命令关系类图:

命令模式类图1

2 示例

本例子是呼叫小爱同学帮你开灯的例子,你对小爱同学说:小爱同学帮我打开灯,然后小爱同学让灯自己打开了。

抽象命令接口Command:

1
2
3
4
5
6
7
8
9
/**
* 抽象的命令接口,定义具体命名的接口
*/
public interface Command {
/**
* 执行命名的接口
*/
void execute();
}

具体的命令对象ConcreteCommand:(开灯命令,关灯命令)

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 LightOnCommand implements Command{

private Light light;

/**
* 创建开灯命令的时候,传入具体的灯对象,由灯对象操作自己
* @param light
*/
public LightOnCommand(Light light) {
this.light = light;
}

@Override
/**
* 具体的灯对象调用自己的开灯方法
*/
public void execute() {
light.lightOn();
}
}
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 LightOffCommand implements Command{

private Light light;

/**
* 创建关灯命令的时候,传入具体的灯对象,由灯对象操作自己
* @param light
*/
public LightOffCommand(Light light) {
this.light = light;
}

@Override
/**
* 具体的灯对象调用自己的关灯方法
*/
public void execute() {
light.lightOff();
}
}

传递命令对象Invoker:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 小爱同学
*/
public class XiaoAi {

private Command command;

/**
* 设置具体的命令
* @param command
*/
public void setCommand(Command command) {
this.command = command;
}

/**
* 执行命令
*/
public void doCommand() {
command.execute();
}
}

接受者对象Receiver:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 具体的电灯类
*/
public class Light {

/**
* 开灯方法
*/
public void lightOn() {
System.out.println("灯打开了!!");
}

/**
* 关灯方法
*/
public void lightOff() {
System.out.println("灯关上了!!");
}
}

客户端对象:

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
/**
* 客户端对象
*/
public class Client {

public static void main(String[] args) {
// 创建小爱同学
XiaoAi xiaoAi = new XiaoAi();
// 创建具体的等对象,相当于具体的命令接受者
Light light = new Light();
// 创建了开灯的命令,你就是命令的发起者
System.out.println("小爱同学帮我把灯开一下!");
LightOnCommand lightOnCommand = new LightOnCommand(light);
// 小爱同学接受到了你发出的命令,并执行命令
xiaoAi.setCommand(lightOnCommand);
xiaoAi.doCommand();

System.out.println("-------------------------------------------------");
System.out.println("小爱同学帮我关一下灯!");
LightOffCommand lightOffCommand = new LightOffCommand(light);
xiaoAi.setCommand(lightOffCommand);
xiaoAi.doCommand();

}
}

测试结果:

1
2
3
4
5
小爱同学帮我把灯开一下!
灯打开了!!
-------------------------------------------------
小爱同学帮我关一下灯!
灯关上了!!

3 命令模式的优缺点

优点:

  • 实现客户端和接受者之间的解耦。
  • 可以动态的添加新的命令。
  • 只需要调用同一个方法(doCommand方法)便可以实现不同的功能。

缺点:

  • 实现一个具体的命令系统,可能要创建很多的具体命令对象。