行为型 中等

命令模式

Command Pattern

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

概述

命令模式是一种行为设计模式,它可将请求转换为一个包含与请求相关的所有信息的独立对象。此转换让你能根据不同的请求将方法参数化、延迟请求执行或将其放入队列中,且能实现可撤销操作。

适用场景

  • 当需要通过操作来参数化对象时
  • 当需要将操作放入队列中、延迟执行或远程执行时
  • 当需要实现操作回滚功能时
  • 当需要实现宏命令(组合多个命令)时
  • 当需要记录操作历史以便撤销/重做时

优点

  • +单一职责原则:将触发操作的对象与执行操作的对象解耦
  • +开闭原则:可以在不更改现有代码的情况下引入新命令
  • +可以实现撤销和重做
  • +可以实现操作的延迟执行
  • +可以将多个命令组合成宏命令

缺点

  • 代码可能会变得更加复杂,因为需要引入许多新的类
  • 每个具体命令都需要创建一个类,可能导致类数量膨胀

结构

classDiagram class Command { <<interface>> +execute() +undo() } class ConcreteCommand { -receiver: Receiver -state: any +execute() +undo() } class Invoker { -commandHistory: Command[] -currentCommand: Command +setCommand(cmd: Command) +executeCommand() +undoCommand() +redoCommand() } class Receiver { -state: any +action() +undoAction() +getState() } class Client { +main() } Command <|.. ConcreteCommand : implements ConcreteCommand --> Receiver : uses Invoker o--> Command : stores Client ..> Invoker : uses Client ..> Receiver : creates style Command fill:#e3f2fd,stroke:#1976d2,stroke-width:2px style ConcreteCommand fill:#e8f5e9,stroke:#388e3c,stroke-width:2px style Invoker fill:#fff3e0,stroke:#f57c00,stroke-width:2px style Receiver fill:#fce4ec,stroke:#c2185b,stroke-width:2px style Client fill:#f5f5f5,stroke:#616161,stroke-width:1px

交互演示

将请求封装为对象
InvokerRemote
命令队列
Receiver
OFF

添加命令到队列,然后执行。命令模式将请求的发送者和接收者解耦。

生活类比

命令模式就像是餐厅点餐系统

餐厅点餐

服务员接受你的订单(命令),将其放入队列,厨师按顺序执行。你可以取消订单(撤销),也可以要求重做(重做)。

遥控器

电视遥控器上的每个按钮都是一个命令。按"开"按钮发送开灯命令,按"关"按钮发送关灯命令,还可以有"撤销"按钮撤销上一步操作。

文本编辑器

文本编辑器中的撤销/重做功能就是命令模式的典型应用。每次编辑操作都被封装为命令并保存到历史记录中。

代码实现

Example.java

实际应用

Java Runnable

Java 的 Runnable 接口是命令模式的典型应用,将可执行代码封装为对象。

Example.java

GUI 撤销/重做

文本编辑器、图像编辑软件中的撤销/重做功能通常使用命令模式实现。

Example.java

数据库事务

数据库事务管理使用命令模式来封装 SQL 操作,支持提交和回滚。

Example.java

练习

1

命令模式的主要目的是什么?

2

命令模式可以实现撤销和重做功能

3

在命令模式中,实际执行业务逻辑的是哪个角色?