设计模式系列:一文带你了解“命令模式”

基本介绍

我们日常的开发就很好地体现出了命令模式,比如:领导将开发任务指派给程序员去完成。其中领导就是“命令的发布者(调用者)”,程序员就是“命令的具体执行者(接收者)”,这个指派的动作就是“具体的命令”。命令将调用者和接收者进行连接,从而完成开发任务,这一套流程就可以看作是命令模式的执行原理。

命令模式使得请求的发送者与请求的执行者之间消除耦合,让对象之间的调用关系更加灵活。在命令模式中,会将一个命令封装成一个对象,同时命令模式也支持可撤销的操作。

命令模式UML类图

在这里插入图片描述

UML类图讲解

Invoker:调用者角色。
Command:抽象命令角色,封装了所有需要执行的命令,可以是抽象类或接口。
Receiver:接收者角色,具体执行命令的类。
ConcreteCommand:具体命令角色,实现了Command类,并聚合了Receiver类。该类的作用是将一个接收者对象与一个命令进行绑定。

案例讲解

通过上面的介绍相信大家对命令模式模式有了一个简单的认识,下面让我们通过一个案例来加深对该模式的理解。

案例:实现通过遥控器开关电视以及撤销上一次操作的功能。

命令接口 => 对应抽象命令角色

public interface Command {

  // 执行操作
  void execute();

  // 撤销操作
  void undo();

}

电视 => 对应接收者角色

public class TVReceiver {

  public void on() {
    System.out.println("电视机打开了。");
  }

  public void off() {
    System.out.println("电视机关闭了。");
  }
  
}

具体命令实现类

/**
 * 开电视
 */
public class TVOnCommand implements Command {

  // 聚合TVReceiver
  private TVReceiver tv;

  public TVOnCommand(TVReceiver tv) {
    this.tv = tv;
  }
  
  @Override
  public void execute() {
    // 执行打开电视机命令
    this.tv.on();
  }

  @Override
  public void undo() {
    // 执行关闭电视机命令,因为打开电视对应的就是关闭。
    this.tv.off();
  }
}

/**
 * 关闭电视
 */
public class TVOffCommand implements Command {

  // 聚合TVReceiver
  private TVReceiver tv;

  public TVOffCommand(TVReceiver tv) {
    this.tv = tv;
  }

  @Override
  public void execute() {
    // 执行关闭电视机命令
    this.tv.off();
  }

  @Override
  public void undo() {
    // 执行打开电视机命令,因为关闭电视机对应的就是打开。
    this.tv.on();
  }
}

/**
 * 空命令
 *  该类默认实现Command接口,不执行任何命令。添加该类的作用是
 *  为了省略执行操作时对空的判断。
 */
public class NoCommand implements Command {

  @Override
  public void execute() {

  }

  @Override
  public void undo() {

  }
}

遥控器 => 对应调用者角色

public class RemoteController {
  // 开按钮的命令
  private Command onCommand = new NoCommand();
  // 关按钮的命令
  private Command offCommand = new NoCommand();
  // 执行撤销的命令
  private Command undoCommand = new NoCommand();

  // 给按钮设置相关命令
  public void setCommand(Command onCommand, Command offCommand) {
    this.onCommand = onCommand;
    this.offCommand = offCommand;
  }

  // 按下打开按钮
  public void onButtonWasPushed() {
    this.onCommand.execute();
    // 记录本次操作
    this.undoCommand = this.onCommand;
  }

  // 按下关闭按钮
  public void offButtonWasPushed() {
    this.offCommand.execute();
    // 记录本次操作
    this.undoCommand = this.offCommand;
  }

  // 按下撤销按钮
  public void undoButtonWasPushed() {
    this.undoCommand.undo();
  }
}

客户端测试类

public class Client {

  public static void main(String[] args) {
    // 创建电视机接收者
    TVReceiver tvReceiver = new TVReceiver();

    // 创建电视机开关命令
    TVOnCommand tvOnCommand = new TVOnCommand(tvReceiver);
    TVOffCommand tvOffCommand = new TVOffCommand(tvReceiver);

    // 创建遥控器
    RemoteController remoteController = new RemoteController();
    // 设置命令
    remoteController.setCommand(tvOnCommand, tvOffCommand);

    System.out.println("======按下打开按钮======");
    remoteController.onButtonWasPushed();
    System.out.println("======按下关闭按钮======");
    remoteController.offButtonWasPushed();
    System.out.println("======撤销上次操作======");
    remoteController.undoButtonWasPushed();
  }
}

执行结果

在这里插入图片描述

总结

优点

1、调用者只需要调用命令对象的“执行”方法就可以让接收者工作,而不必知道具体是谁接收的命令,命令是如何被执行的。将发起命令请求的对象和执行命令的对象拆分开从而促使代码解耦,通过这样的设计将利于程序的扩展。
2、通过添加一个“空命令”来省去判空的操作。
3、通过添加撤销方法可以实现对命令的撤销重做。

缺点:

造成系统存在过多的具体命令类,增加系统的复杂度。

注意

命令对象负责让具体的接收者执行指定的操作,它就是连接“请求发起者”和“请求执行者”的桥梁。

今天的分享就到这里了,如果感觉“菜鸟”写的文章还不错,记得点赞关注呦!你们的支持就是我坚持下去的动力。文章哪里写的有问题的也希望大家可以指出,我会虚心受教。

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值