设计模式之命令模式

Posted ProChick

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之命令模式相关的知识,希望对你有一定的参考价值。

1.简要概述

  • 命令模式就是将一个请求封装为一个对象,从而使我们可对不同的请求进行参数化,也就是使用不同的参数来表示不同的请求。
  • 命令模式使用命令来参数化其它对象、将命令放入队列中进行排队、将命令的操作记录到日志中。
  • 命令模式支持可撤销的操作。

2.模式结构

👉通常由一个调用者类( 负责调用命令来执行特定操作,也叫作请求的发送者 ),一个接受者类( 负责执行命令的相关操作,实现具体的业务 ),一个抽象命令类( 负责定义命令执行、撤销等接口 ),多个具体命令类( 负责将命令与接收者进行绑定,通知接受者执行命令 ),一个客户类( 负责创建调用者对象和一些具体的命令对象,完成某些操作)共同组成。

3.实现代码

举例 💡 :假设我们现在有一个智能遥控器,遥控器上有电灯的开关按钮、有电视的开关按钮、有空调的开关按钮等等,这些开关操作我们就可以看作是一个一个的命令,那么遥控器、按钮、电器它们之间的关系我们就可以使用命令模式来表示。

抽象命令类

public interface Command {
    void execute();
    
    void undo();
}

电灯开命令(具体命令类)

public class LightOnCommand implements Command {
    private Light light;

    public LightOnCommand(Light light) {
        super();
        this.light = light;
    }

    @Override
    public void execute() {
        light.on();
    }
    
    @Override
    public void undo() {
        light.off();
    }
}

电灯关命令(具体命令类)

public class LightOffCommand implements Command {
    private Light light;

    public LightOffCommand(Light light) {
        super();
        this.light = light;
    }

    @Override
    public void execute() {
        light.off();
    }
    
    @Override
    public void undo() {
        light.on();
    }
}

电灯类(接收者)

public class Light {

    public void on() {
        System.out.println("打开电灯");
    }

    public void off() {
        System.out.println("关闭电灯");
    }
}

遥控器类(调用者)

public class RemoteControl {
    private Command[] onCommands;
    private Command[] offCommands;
    private Command undoCommand;
    private final int NUM = 5;

    public RemoteControl() {
        this.onCommands = new Command[NUM];
        this.offCommands = new Command[NUM];
    }

    public void setOnCommand(Command command, int index) {
        onCommands[index] = command;
    }

    public void setOffCommand(Command command, int index) {
        offCommands[index] = command;
    }

    public void sendOnCommand(int index) {
        onCommands[index].execute();
        undoCommand = onCommands[index];
    }

    public void sendOffCommand(int index) {
        offCommands[index].execute();
        undoCommand = offCommands[index];
    }
    
    public void sendUndoCommand() {
        undoCommand.undo();
    }
}

客户类

// 测试客户端
public class CommandClient{
    public static void main(String[] args) {
        Light light = new Light();
        Command lightOnCommand = new LightOnCommand(light);
        Command lightOffCommand = new LightOffCommand(light);
        
        RemoteControl rc = new RemoteControl();
        rc.setOnCommand(lightOnCommand, 0);
        rc.setOffCommand(lightOffCommand, 0);
        
        rc.sendOnCommand(0);  // 打开电灯
        rc.sendOffCommand(0); // 关闭电灯
        rc.sendUndoCommand(); // 打开电灯
    }
}

4.优点好处

  • 命令模式使得请求发送者与请求接受者消除了彼此之间的耦合,调用者只需要调用相关命令对象的某个方法即可,不需要知道具体的接收者是谁,也就使得了它们之间的调用更加灵活。
  • 命令模式屏蔽了底层的复杂实现,对外提供了统一的表现。
  • 命令模式可以记录请求操作的历史记录,以及回撤请求操作。
  • 命令模式具有很好的拓展性,可以很方便地添加新的命令。

5.缺点弊端

使用命令模式可能会导致系统中会有过多的具体命令类,导致代码复杂度很高,因为针对每一个命令都需要设计一个具体命令实现类。

6.应用场景

  • 当系统中的某项操作需要实现多级撤销回退功能的时候使用。
  • 当系统需要在不同的时间指定请求、将请求排队和执行请求的时候使用。
  • 当客户端向某些对象发送请求,但是并不能确定请求接受者是谁、请求具体操作是什么的时候使用。
  • 当系统中实现某个操作需要按照一定顺序来执行一系列命令请求操作的时候使用。

7.应用示例

Spring框架源码中关于JdbcTemplate类中执行excute方法的过程

  1. 这里的StatementCallback接口,好比是命令模式中的命令接口,里面定义了一个doInStatement方法。

  2. 下面的实现类就好比是命令模式中的具体命令类,以QueryStatementCallback类为例,它实现了doInStatement方法,并且它可以充当命令的接受者聚合了自己,是一个内部类。

  3. 这里的JdbcTemplate类相当于命令的调用者,下面的execute方法就需要传入一个具体的命令实现类,来完成指定命令的操作。

以上是关于设计模式之命令模式的主要内容,如果未能解决你的问题,请参考以下文章

学习设计模式之命令模式

设计模式之命令模式-使用命令模式实现遥控器及总结

入门设计模式之命令模式

设计模式之Command(命令)(转)

设计模式之命令模式20170719

设计模式之命令模式