设计模式-命令模式

要理解设计模式中的命令模式,我们可以从其核心思想入手:将请求封装为一个对象,从而实现请求的参数化、排队、日志记录或撤销等功能。它本质上是通过“命令对象”作为中间层,解耦了“请求的发送者”和“请求的执行者”。

一、命令模式的核心角色

命令模式包含5个核心角色,各自职责如下:

角色 职责描述
命令接口(Command) 声明执行操作的方法(如execute()),通常还会声明撤销操作的方法(如undo())。
具体命令(ConcreteCommand) 实现命令接口,绑定一个“接收者”,并在execute()中调用接收者的具体操作。
接收者(Receiver) 实际执行命令操作的对象(知道如何处理请求)。
调用者(Invoker) 持有命令对象,负责触发命令的执行(如调用execute())。
客户端(Client) 创建具体命令对象,绑定接收者,并将命令对象交给调用者。

二、Java代码演示

我们以“遥控器控制家电”为例(遥控器是调用者,家电是接收者),演示命令模式的实现。

1. 定义命令接口(Command)

声明执行和撤销的核心方法:

// 命令接口
public interface Command {
    // 执行命令
    void execute();
    // 撤销命令
    void undo();
}

2. 定义接收者(Receiver)

接收者是实际执行操作的对象(如电灯、电视):

// 电灯(接收者)
public class Light {
    private String location; // 位置(如客厅、卧室)

    public Light(String location) {
        this.location = location;
    }

    // 开灯操作
    public void turnOn() {
        System.out.println(location + " 电灯已打开");
    }

    // 关灯操作
    public void turnOff() {
        System.out.println(location + " 电灯已关闭");
    }
}

// 电视(接收者)
public class TV {
    private String location;

    public TV(String location) {
        this.location = location;
    }

    // 开电视操作
    public void turnOn() {
        System.out.println(location + " 电视已打开");
    }

    // 关电视操作
    public void turnOff() {
        System.out.println(location + " 电视已关闭");
    }
}

3. 定义具体命令(ConcreteCommand)

实现命令接口,绑定接收者并封装具体操作:

// 开灯命令
public class LightOnCommand implements Command {
    private Light light; // 绑定的接收者(电灯)

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

    @Override
    public void execute() {
        light.turnOn(); // 调用电灯的“开”操作
    }

    @Override
    public void undo() {
        light.turnOff(); // 撤销:执行相反操作(关灯)
    }
}

// 关灯命令
public class LightOffCommand implements Command {
    private Light light;

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

    @Override
    public void execute() {
        light.turnOff(); // 调用电灯的“关”操作
    }

    @Override
    public void undo() {
        light.turnOn(); // 撤销:执行相反操作(开灯)
    }
}

// 开电视命令
public class TVOnCommand implements Command {
    private TV tv; // 绑定的接收者(电视)

    public TVOnCommand(TV tv) {
        this.tv = tv;
    }

    @Override
    public void execute() {
        tv.turnOn(); // 调用电视的“开”操作
    }

    @Override
    public void undo() {
        tv.turnOff(); // 撤销:执行相反操作(关电视)
    }
}

// 关电视命令
public class TVOffCommand implements Command {
    private TV tv;

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

    @Override
    public void execute() {
        tv.turnOff(); // 调用电视的“关”操作
    }

    @Override
    public void undo() {
        tv.turnOn(); // 撤销:执行相反操作(开电视)
    }
}

4. 定义调用者(Invoker)

调用者持有命令对象,并触发命令的执行(如遥控器):

// 遥控器(调用者)
public class RemoteControl {
    private Command currentCommand; // 当前要执行的命令
    private Command lastCommand; // 记录上一次执行的命令(用于撤销)

    // 设置当前命令
    public void setCommand(Command command) {
        this.currentCommand = command;
    }

    // 按下“执行”按钮
    public void pressExecuteButton() {
        currentCommand.execute();
        lastCommand = currentCommand; // 保存当前命令,用于后续撤销
    }

    // 按下“撤销”按钮
    public void pressUndoButton() {
        if (lastCommand != null) {
            lastCommand.undo();
        } else {
            System.out.println("没有可撤销的命令");
        }
    }
}

5. 客户端(Client)测试

客户端创建对象并组装关系,模拟操作流程:

public class Client {
    public static void main(String[] args) {
        // 1. 创建接收者(家电)
        Light livingRoomLight = new Light("客厅");
        TV bedroomTV = new TV("卧室");

        // 2. 创建具体命令(绑定接收者)
        Command lightOn = new LightOnCommand(livingRoomLight);
        Command lightOff = new LightOffCommand(livingRoomLight);
        Command tvOn = new TVOnCommand(bedroomTV);
        Command tvOff = new TVOffCommand(bedroomTV);

        // 3. 创建调用者(遥控器)
        RemoteControl remote = new RemoteControl();

        // 4. 模拟操作:开客厅灯
        remote.setCommand(lightOn);
        remote.pressExecuteButton(); // 输出:客厅 电灯已打开

        // 5. 撤销:关闭客厅灯
        remote.pressUndoButton(); // 输出:客厅 电灯已关闭

        // 6. 模拟操作:开卧室电视
        remote.setCommand(tvOn);
        remote.pressExecuteButton(); // 输出:卧室 电视已打开

        // 7. 模拟操作:关卧室电视
        remote.setCommand(tvOff);
        remote.pressExecuteButton(); // 输出:卧室 电视已关闭

        // 8. 撤销:打开卧室电视
        remote.pressUndoButton(); // 输出:卧室 电视已打开
    }
}

三、命令模式的优点

  1. 解耦发送者和接收者:调用者(如遥控器)无需知道接收者(如家电)的具体实现,只需通过命令对象间接交互。
  2. 易扩展:新增命令时,只需新增具体命令类,无需修改调用者或接收者(符合“开闭原则”)。
  3. 支持复杂操作:可实现命令排队(如批量执行)、日志记录(如记录操作历史)、撤销/重做等功能。

通过这个例子,我们可以清晰看到:命令模式将“操作请求”封装为独立的命令对象,使得请求的发送和执行完全分离,极大提升了系统的灵活性。

posted @ 2025-11-05 09:29  fishyy  阅读(0)  评论(0)    收藏  举报