设计模式-命令模式

命令模式(Command Pattern): 将一个请求封装成一个对象, 从而可以用不同请求对客户进行参数化, 对请求队列或者记录请求日志, 以及支持可撤销的操作.

设计模式-概述

命令模式实现了请求的发送者与请求的执行者完全解耦, 发送者与执行者之间没有直接引用关系, 中间由命令来连接, 发送方不用了解执行过程.

结构

命令模式有4个成员:

  1. Command(抽象命令类)
  2. ConcreteCommand(具体命令类)
  3. Invoker(调用者)
  4. Receiver(接收者)

command-1.png

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
@startuml command-1
!include common.cuml

Class(Receiver,"接收者") {
+ action() : void
}

Class(Command,"抽象命令接口") <<abstract>> {
+ execute() : void
}

Class(ConcreteCommand,"具体命令类") {
- state : State
+ execute() : void
}

Class(Invoker,"调用者") {
+ call() : void
}

Class(Client,"客户端") {
}

note AS N1
receiver.action();
end note

Receiver <-left- ConcreteCommand : receiver
ConcreteCommand .up.|> Command
Invoker o-right-> Command
N1 -up- ConcreteCommand
Client .right.> Invoker : 2
Client .right.> ConcreteCommand : 1
@enduml

使用时序

command-2.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@startuml command-2
!include common.cuml
participant Client as U
participant Receiver as R
participant ConcreteCommand as C
participant Invoker as I

U --> R : new Recever();
activate U
U -> C : new ConcreteCommand(receiver)
U -> I : new Invoker(command)
deactivate U
U --> I : call()
activate I
activate U
I --> C : execute()
activate C
C --> R : action()
activate R
@enduml

命令队列与宏命令

  1. 命令队列
    Invoke角色内的成员可以替换为CommandQueue, 来实现命令队列方式的执行.

    CommandQueue 内部成员变量是一个 List<Command>, execute()方法通过for循环依次执行command对象的execute()方法.

  2. 宏命令
    与命令队列不同的是, 它的commond本身内部可以保存一个command集合, 一组命令可以包含在一个command中.

代码实现

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
public class Client {
public static void main(String[] args) {
Receiver receiver = new Receiver();
ConcreteCommand concreteCommand = new ConcreteCommand(receiver);
Invoke invoke = new Invoke(concreteCommand);
invoke.execute();
}
}

class Invoke {
private Command command;

Invoke(Command command) {
this.command = command;
}

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

class Receiver {
public void action() {
System.out.println("执行操作");
}
}

abstract class Command {
public abstract void execute();
}

class ConcreteCommand extends Command {

private Receiver receiver;

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

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

使用场景

  • 需要请求者和请求接收者解耦, 使得调用者和接收者不直接交互.
  • 调用者和接收者生命期可以不同, 调用者不存在, 接收者也可以是活动的.
  • 如果需要指出撤销和恢复操作
  • 如果有一组命令需要合并成宏命令

具体应用

Spring Cloud Hystrix 使用命令模式来执行请求.