文章

命令模式

命令模式

命令模式

什么是命令模式?

命令模式的定义

Encapsulate a request as an object,thereby letting you parameterize clients with different requests,queue or log requests,and support undoable operations.(将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。)

命令模式的核心在于引入了命令类,通过命令类来降低发送者和接收者的耦合度,请求发送者只需指定一个命令对象,再通过命令对象来调用请求接收者的处理方法。

命令模式通用类图

l7zy8

命令模式包含这么几个角色:

  • Command(抽象命令):声明需要执行的命令
  • ConcreteCommand(具体的命令,可能有多个):实现声明的命令
  • Receive(接收者,具体业务实现者):接收者执行与请求相关的操作,它具体实现对请求的业务处理
  • Invoker(调用者):调用者即请求发送者,它通过命令对象来执行请求。

命令模式的本质是对请求进行封装,一个请求对应于一个命令,将发出命令的责任和执行命令的责任分割开。每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行相应的操作。命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求如何被接收、操作是否被执行、何时被执行,以及是怎么被执行的。

案例

案例 1

  • Receiver:Receiver 类实现具体的业务需求
1
2
3
4
5
6
7
8
9
/**
 * Receiver类实现具体的业务需求
 */
public class Receiver {
    public void doSomething() {
        // 具体的业务逻辑
        System.out.println("Receiver类实现具体的业务需求");
    }
}
  • 接口的 Command 类定义命令:
1
2
3
4
5
6
7
/**
 * 命令接口
 */
public interface Command {
    // 每个命令类都必须有一个执行命令的方法
    void execute();
}
  • 具体的 Command 类:根据需求,具体的命令类可以有多个:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
 * 具体的Command类:根据需求,具体的命令类可以有多个
 */
public class ConcreteCommand1 implements Command {

    // 维持一个对请求接收者对象的引用
    private Receiver receiver;

    // 构造函数传递接收者
    public ConcreteCommand1(Receiver receiver) {
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        // 调用请求接收者的业务处理方法doSomething()
        receiver.doSomething();
    }
}
  • 调用者 Invoker 类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
 * 调用者Invoker类
 */
public class Invoker {

    private Command command;

    // 设值注入
    public void setCommand(Command command) {
        this.command = command;
    }

    // 执行命令
    public void action() {
        this.command.execute();
    }
}
  • 场景类:
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Client {
    public static void main(String[] args) {
        // 首先声明调用者Invoker
        Invoker invoker = new Invoker();
        // 定义接收者
        Receiver receiver = new Receiver();
        // 定义一个发送给接收者的命令
        Command command = new ConcreteCommand1(receiver);
        // 把命令交给调用者去执行
        invoker.setCommand(command);
        invoker.action();
    }
}

命令模式使用场景

  1. 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。请求调用者 无须知道接收者的存在,也无须知道接收者是谁,接收者也无须关心何时被调用。
  2. 系统需要在不同的时间指定请求、将请求排队和执行请求。一个命令对象和请求的初始调 用者可以有不同的生命期,换言之,最初的请求发出者可能已经不在了,而命令对象本身仍 然是活动的,可以通过该命令对象去调用请求接收者,而无须关心请求调用者的存在性,可以通过请求日志文件等机制来具体实现。
  3. 系统需要支持命令的撤销 (Undo) 操作和恢复 (Redo) 操作。

Ref

本文由作者按照 CC BY 4.0 进行授权