【命令模式】

3 阅读3分钟

定义

命令模式(Command Pattern)是一种行为型设计模式,它将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

以下是命令模式的主要特点和定义:

主要角色

  1. Command(抽象命令类)

    • 声明执行操作的接口,通常包含一个execute方法用于执行命令。
  2. ConcreteCommand(具体命令类)

    • 实现抽象命令类,将一个接收者对象绑定于一个动作。
    • 调用接收者相应的操作,以实现execute方法。
  3. Receiver(接收者对象)

    • 知道如何实施与执行一个与请求相关的操作。
  4. Invoker(调用者)

    • 要求该命令执行这个请求。

业务

假设我们有一个电灯系统,有开灯和关灯的操作。

classDiagram
    class Command {
        +execute() : void
    }
    class LightOnCommand {
        -Light light
        +execute() : void
    }
    class LightOffCommand {
        -Light light
        +execute() : void
    }
    class Light {
        +turnOn() : void
        +turnOff() : void
    }
    class RemoteControl {
        -Command command
        +setCommand(Command) : void
        +pressButton() : void
    }
    Command <|-- LightOnCommand
    Command <|-- LightOffCommand
    LightOnCommand --> Light
    LightOffCommand --> Light
    RemoteControl "1" --> "1" Command

一、定义接收者(Receiver)

首先定义电灯类作为接收者:

class Light {
    public void turnOn() {
        System.out.println("Light is on.");
    }

    public void turnOff() {
        System.out.println("Light is off.");
    }
}

二、定义抽象命令(Command)

创建一个命令接口:

interface Command {
    void execute();
}

三、定义具体命令(ConcreteCommand)

实现开灯和关灯的具体命令类:

class LightOnCommand implements Command {
    private Light light;

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

    @Override
    public void execute() {
        light.turnOn();
    }
}

class LightOffCommand implements Command {
    private Light light;

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

    @Override
    public void execute() {
        light.turnOff();
    }
}

四、定义调用者(Invoker)

class RemoteControl {
    private Command command;

    public void setCommand(Command command) {
        this.command = command;
    }

    public void pressButton() {
        command.execute();
    }
}

五、使用命令模式

public class CommandPatternExample {
    public static void main(String[] args) {
        Light light = new Light();
        LightOnCommand onCommand = new LightOnCommand(light);
        LightOffCommand offCommand = new LightOffCommand(light);

        RemoteControl remote = new RemoteControl();

        remote.setCommand(onCommand);
        remote.pressButton();

        remote.setCommand(offCommand);
        remote.pressButton();
    }
}

在这个例子中,电灯(Light)是接收者,命令接口(Command)定义了执行命令的方法,具体命令类(LightOnCommandLightOffCommand)实现了命令接口并调用接收者的相应方法,遥控器(RemoteControl)是调用者,负责执行命令。通过这种方式,命令模式将请求的发送者(遥控器)和请求的接收者(电灯)解耦,使得可以方便地添加新的命令和调用者,而不需要修改现有的代码。

总结

使用场景

  1. 需要将请求调用者和请求接收者解耦。

    • 例如在图形用户界面中,一个按钮的点击事件可以被封装成一个命令对象,按钮只需要触发命令的执行,而不需要知道具体的操作是由哪个对象来执行。
  2. 需要支持可撤销的操作。

    • 可以将每个操作封装成一个命令对象,记录命令执行前的状态,以便在需要撤销时恢复到之前的状态。
  3. 需要支持宏命令,即一组命令的组合执行。

    • 可以创建一个包含多个命令对象的宏命令对象,依次执行这些命令。

优点

  1. 降低了系统的耦合度。

    • 请求调用者和请求接收者之间没有直接的代码耦合,通过命令对象进行间接的交互。
  2. 易于实现可撤销的操作。

    • 可以方便地记录命令执行前的状态,以便在需要时进行撤销。
  3. 易于扩展新的命令。

    • 只需要实现新的具体命令类,而不需要修改现有的代码。

缺点

  1. 可能会导致系统中出现过多的具体命令类,增加系统的复杂性。
  2. 命令的执行可能会依赖于接收者的状态,如果接收者状态发生变化,可能会影响命令的执行结果。