Book-深入设计模式-命令模式

Book-深入设计模式-命令模式

https://refactoringguru.cn/design-patterns/command

命令模式
亦称: 动作、事务、Action、Transaction、Command

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

优秀的软件设计通常会将关注点进行分离, 而这往往会导致软件的分层。

命令模式结构

![](.\command structure.png)
command structure

命令模式适合应用场景

  1. 如果你需要通过操作来参数化对象, 可使用命令模式。
    命令模式可将特定的方法调用转化为独立对象。 这一改变也带来了许多有趣的应用: 你可以将命令作为方法的参数进行传递、 将命令保存在其他对象中, 或者在运行时切换已连接的命令等。
    举个例子: 你正在开发一个 GUI 组件 (例如上下文菜单), 你希望用户能够配置菜单项, 并在点击菜单项时触发操作。

  2. 如果你想要将操作放入队列中、 操作的执行或者远程执行操作, 可使用命令模式。
    同其他对象一样, 命令也可以实现序列化 (序列化的意思是转化为字符串), 从而能方便地写入文件或数据库中。 一段时间后, 该字符串可被恢复成为最初的命令对象。 因此, 你可以延迟或计划命令的执行。 但其功能远不止如此! 使用同样的方式, 你还可以将命令放入队列、 记录命令或者通过网络发送命令。

  3. 如果你想要实现操作回滚功能, 可使用命令模式。
    尽管有很多方法可以实现撤销和恢复功能, 但命令模式可能是其中最常用的一种。
    为了能够回滚操作, 你需要实现已执行操作的历史记录功能。 命令历史记录是一种包含所有已执行命令对象及其相关程序状态备份的栈结构。
    这种方法有两个缺点。 首先, 程序状态的保存功能并不容易实现, 因为部分状态可能是私有的。 你可以使用备忘录模式来在一定程度上解决这个问题。
    其次, 备份状态可能会占用大量内存。 因此, 有时你需要借助另一种实现方式: 命令无需恢复原始状态, 而是执行反向操作。 反向操作也有代价: 它可能会很难甚至是无法实现。

实现方式

  1. 声明仅有一个执行方法的命令接口。

  2. 抽取请求并使之成为实现命令接口的具体命令类。 每个类都必须有一组成员变量来保存请求参数和对于实际接收者对象的引用。 所有这些变量的数值都必须通过命令构造函数进行初始化。

  3. 找到担任发送者职责的类。 在这些类中添加保存命令的成员变量。 发送者只能通过命令接口与其命令进行交互。 发送者自身通常并不创建命令对象, 而是通过客户端代码获取。

  4. 修改发送者使其执行命令, 而非直接将请求发送给接收者。

  5. 客户端必须按照以下顺序来初始化对象:

    • 创建接收者。
    • 创建命令, 如有需要可将其关联至接收者。
    • 创建发送者并将其与特定命令关联。

命令模式优缺点

优点

  • 单一职责原则。 你可以解耦触发和执行操作的类。
  • 开闭原则。 你可以在不修改已有客户端代码的情况下在程序中创建新的命令。
  • 你可以实现撤销和恢复功能。
  • 你可以实现操作的延迟执行。
  • 你可以将一组简单命令组合成一个复杂命令。

缺点
代码可能会变得更加复杂, 因为你在发送者和接收者之间增加了一个全新的层次。

与其他模式的关系

  • 责任链模式、 命令模式、 中介者模式和观察者模式用于处理请求发送者和接收者之间的不同连接方式:

    • 责任链按照顺序将请求动态传递给一系列的潜在接收者, 直至其中一名接收者对请求进行处理。
    • 命令在发送者和请求者之间建立单向连接。
    • 中介者清除了发送者和请求者之间的直接连接, 强制它们通过一个中介对象进行间接沟通。
    • 观察者允许接收者动态地订阅或取消接收请求。
  • 责任链的管理者可使用命令模式实现。 在这种情况下, 你可以对由请求代表的同一个上下文对象执行许多不同的操作。
    还有另外一种实现方式, 那就是请求自身就是一个命令对象。 在这种情况下, 你可以对由一系列不同上下文连接而成的链执行相同的操作。

  • 你可以同时使用命令和备忘录模式来实现 “撤销”。 在这种情况下, 命令用于对目标对象执行各种不同的操作, 备忘录用来保存一条命令执行前该对象的状态。

  • 命令和策略模式看上去很像, 因为两者都能通过某些行为来参数化对象。 但是, 它们的意图有非常大的不同。
    你可以使用命令来将任何操作转换为对象。 操作的参数将成为对象的成员变量。 你可以通过转换来延迟操作的执行、 将操作放入队列、 保存历史命令或者向远程服务发送命令等。
    另一方面, 策略通常可用于描述完成某件事的不同方式, 让你能够在同一个上下文类中切换算法。

  • 原型模式可用于保存命令的历史记录。

  • 你可以将访问者模式视为命令模式的加强版本, 其对象可对不同类的多种对象执行操作。

posted @ 2023-03-06 19:49  Theseus‘Ship  阅读(7)  评论(0编辑  收藏  举报
Live2D