设计模式 命令模式(Command Pattern)

命令模式简绍

命令模式(Command Pattern)是一种行为设计模式,它把请求封装成对象,从而让你可以用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。

组成部分:

  • 命令接口(Command Interface):定义执行操作的接口。
  • 具体命令类(Concrete Command Class):实现了命令接口,并拥有接收者对象的引用。
  • 接收者(Receiver):知道如何实施与执行一个请求相关的操作,任何类都可以充当接收者。
  • 调用者(Invoker):请求一个命令对象执行一个请求。

命令模式的优缺点

优点
  • 降低耦合度:
    • 请求发送者不需要知道请求的实际接收者是谁,也不需要知道请求的执行细节。
    • 接收者和请求发送者之间解耦,使得两者可以独立变化。
  • 易于实现撤销和重做功能:
    • 由于每个命令都是一个对象,因此可以保存以前的状态,并在需要时恢复。
    • 支持事务回滚,因为可以存储多个命令,并按顺序或逆序执行。
  • 易于支持事务处理:
    • 可以将多个命令组合成一个宏命令(复合命令),从而实现整体的事务处理(要么全部成功,要么全部失败)。
  • 易于支持队列和日志:
    • 命令对象可以被放入队列中,按照顺序执行。
    • 命令对象也可以被记录下来,用于审计或日志记录。
  • 增加新的命令非常容易:
    • 添加新命令只需要实现命令接口,而不需要修改已有的代码。
    • 这符合开闭原则(Open-Closed Principle),即对扩展开放,对修改关闭。
  • 增强安全性:
    • 可以通过命令对象来验证权限,从而在执行之前检查是否有权限执行该命令。
缺点
  • 可能导致系统复杂度增加:
    • 如果系统中存在大量的命令类,可能会导致类的数量增加,进而使系统变得复杂。
    • 每个命令都需要一个具体的类来实现,这可能会导致类爆炸。
  • 内存消耗增加:
    • 如果命令对象被频繁创建,特别是在需要撤销或重做功能时,可能会导致内存消耗增加。
    • 特别是在没有及时清理不再需要的命令对象时,内存占用会更高。
  • 性能问题:
    • 命令模式增加了额外的抽象层,可能会导致一些性能上的损耗,尤其是在需要频繁执行命令的情况下。
    • 可能不适合简单场景:

对于非常简单的应用场景,使用命令模式可能会显得过于复杂,没有必要引入这种模式。

UML 图

实现代码

命令接口 (CommandInterface)

这个接口声明了所有命令对象都应该遵循的方法签名。

java 复制代码
public interface CommandInterface {
    void execute();

}
具体命令类 (ConcreteCommandClass)

这个类负责调用接收者的 openMobile() 方法,并添加了一些额外的操作(如"掏出口袋")。

java 复制代码
public class ConcreteCommandClass implements CommandInterface{
    private Receiver receiver;

    public ConcreteCommandClass(Receiver receiver){
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        System.out.println("掏出口袋");
        receiver.openMobile();
    }
}
具体命令类 (ConcreteCommandClass1)

这个类负责调用接收者的 closeMoblie() 方法,并添加了一些额外的操作(如"放回口袋")。

public class ConcreteCommandClass1 implements CommandInterface{

    private Receiver receiver;

    public ConcreteCommandClass1(Receiver receiver){
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        receiver.closeMoblie();
        System.out.println("放回口袋");
    }
}
接收者

这个类包含了实际要执行的操作。

java 复制代码
public class Receiver {

    public void openMobile(){
        System.out.println("打开手机");
    }

    public void closeMoblie(){
        System.out.println("关闭手机");
    }

}
主调用 (Main)

在这里创建了具体的命令对象,并调用了它们的 execute() 方法。

java 复制代码
public class Main {
    public static void main(String[] args) {
        ConcreteCommandClass concreteCommandClass = new ConcreteCommandClass(new Receiver());
        concreteCommandClass.execute();
        ConcreteCommandClass1 concreteCommandClass1 = new ConcreteCommandClass1(new Receiver());
        concreteCommandClass1.execute();
    }
}

这个示例展示了命令模式的基本应用,通过将请求封装成对象,使得发送请求的对象和执行请求的对象之间松耦合。

命令模式应用场景

  • 用户界面设计中的按钮和菜单项

    在图形用户界面(GUI)应用程序中,命令模式可以用来处理用户交互事件。例如,当用户点击一个按钮或选择一个菜单项时,可以创建一个命令对象来表示这个请求,然后在适当的时候执行该命令。

  • 宏命令和批处理

    命令模式非常适合于构建宏命令或批处理命令。可以将多个简单的命令组合成一个复合命令,这样就可以一次执行一系列操作。例如,在文本编辑器中,可以定义一个宏来执行一系列编辑命令。

  • 支持撤销功能(Undo/Redo)

    命令模式可以很容易地支持撤销和重做功能。每个命令对象都可以记录其执行前后的状态,这样在需要撤销操作时可以恢复到之前的状态。这对于许多应用程序来说都是非常有用的特性,比如文本编辑器、绘图工具等。

  • 解耦发送者与接收者

    命令模式使得发送者和接收者之间的耦合度降低。发送者只需要知道如何发送命令,而不需要关心命令的具体实现细节。这使得系统更加灵活,可以在运行时动态改变命令的执行方式。

  • 支持事务处理

    在某些情况下,命令模式可以用来模拟事务处理。一组命令可以作为一个整体来执行,如果其中一个命令失败,则整个事务回滚。这对于一些需要保证数据一致性的场景非常有用。

  • 异步命令执行

    命令模式可以用来支持异步命令执行。命令对象可以在创建时立即被处理,也可以存储起来稍后由调度器统一执行。这对于需要异步处理的任务队列非常有用。

  • 多线程环境下的任务调度

    在多线程环境中,命令模式可以用来封装任务,并将其放入线程池中执行。这样可以方便地管理任务的执行顺序和优先级。

实际案例
  • 编辑器中的撤销功能:用户在编辑器中进行了一系列操作,每个操作都被封装成一个命令对象。这些命令对象可以存储在一个栈中,用户可以选择撤销上一步操作,实际上是从栈中取出最后一个命令对象并执行它的撤销方法。
  • 智能家居控制系统:用户可以通过语音助手控制家中的各种设备(如灯光、空调等)。语音助手接收到指令后,可以创建一个命令对象来表示这个请求,并通过网络发送给相应的设备进行处理。
相关推荐
渊渟岳2 小时前
掌握设计模式--装饰模式
设计模式
zh路西法4 小时前
【C++决策和状态管理】从状态模式,有限状态机,行为树到决策树(二):从FSM开始的2D游戏角色操控底层源码编写
c++·游戏·unity·设计模式·状态模式
夏旭泽5 小时前
设计模式-备忘录模式
设计模式·备忘录模式
沐泽Mu5 小时前
嵌入式学习-QT-Day07
c++·qt·学习·命令模式
蓝染-惣右介5 小时前
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
java·设计模式
捕鲸叉9 小时前
C++软件设计模式之类型模式和对象型模式
开发语言·c++·设计模式
诸葛悠闲10 小时前
设计模式——组合模式
设计模式·组合模式
诸葛悠闲10 小时前
设计模式——装饰模式
设计模式
西岭千秋雪_10 小时前
设计模式の中介者&发布订阅&备忘录模式
java·观察者模式·设计模式·中介者模式·备忘录模式