命令模式(Command Pattern)详解

1. 什么是命令模式?

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

简单来说,命令模式就是将"请求"转化为一个对象,这个对象可以被存储、传递、调用,而且可以在不同的时间点被请求调用,即使发送请求的对象已经不存在。

2. 为什么需要命令模式?

在以下情况下,命令模式特别有用:

  1. 需要参数化操作:当你需要根据运行时确定的请求参数来执行操作时
  2. 需要将操作放入队列:当操作需要排队执行,或者在不同时间执行时
  3. 需要支持撤销/重做功能:当系统需要支持操作的撤销和重做功能时
  4. 需要支持事务:当操作需要作为一个事务执行,要么全部完成,要么全部不做
  5. 需要将发送者与接收者解耦:当请求发送者不需要知道请求如何被处理以及由谁处理时

3. 命令模式的核心概念

命令模式涉及以下几个核心角色:

  1. 命令(Command)

    • 声明执行操作的接口
    • 通常只有一个执行方法(如execute()
  2. 具体命令(Concrete Command)

    • 实现命令接口
    • 通常持有接收者的引用
    • 调用接收者的相关操作来完成命令的执行
  3. 接收者(Receiver)

    • 知道如何实施与命令相关的操作
    • 任何类都可以作为接收者
  4. 调用者(Invoker)

    • 要求命令对象执行请求
    • 不知道命令是如何执行的,也不知道具体的接收者是谁
  5. 客户端(Client)

    • 创建具体的命令对象并设置它的接收者
    • 将命令对象交给调用者

4. 命令模式的结构

命令模式的UML类图如下:

+----------------+       +----------------+
|    Invoker     |------>|    Command     |
+----------------+       +----------------+
                         | execute()      |
                         +----------------+
                                 ↑
                                 |
                         +----------------+
                         |ConcreteCommand |
                         +----------------+
                         | execute()      |
                         +----------------+
                                 |
                                 |
                                 v
                         +----------------+
                         |    Receiver    |
                         +----------------+
                         | action()       |
                         +----------------+

5. 命令模式的基本实现

5.1 简单的灯光控制示例

下面是一个简单的灯光控制示例,展示了命令模式的基本实现。

首先,定义命令接口:

// 命令接口
public interface Command {
   
    void execute();
}

然后,定义接收者类(灯):

// 接收者类
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 LightOnCommand implements Command {
   
    private Light light;
    
    public LightOnCommand(Light light) {
   
        this.light = light;
    }
    
    @Override
    public void execute() {
   
        light.turnOn();
    }
}

// 关闭灯的命令
public class LightOffCommand implements Command {
   
    private Light light;
    
    public LightOffCommand(Light light) {
   
        this.light = light;
    }
    
    @Override
    public void execute() {
   
        light.turnOff();
    }
}

然后,定义调用者类(远程控制器):

// 调用者类
public class RemoteControl {
   
    private Command command;
    
    public void setCommand(Command command) {
   
        this.command = command;
    }
    
    public void pressButton() {
   
        command.execute();
    }
}

最后,客户端代码:

public class CommandPatternDemo {
   
    public static void main(String[] args) {
   
        // 创建接收者
        Light livingRoomLight = new Light("客厅");
        Light kitchenLight = new Light("厨房");
        
        // 创建具体命令
        Command livingRoomLightOn = new LightOnCommand(livingRoomLight);
        Command livingRoomLightOff = new LightOffCommand(livingRoomLight);
        Command kitchenLightOn = new LightOnCommand(kitchenLight);
        Command kitchenLightOff = new LightOffCommand(kitchenLight);
        
        // 创建调用者
        RemoteControl remote = new RemoteControl();
        
        // 使用远程控制器打开客厅灯
        remote.setCommand(livingRoomLightOn);
        remote.pressButton();
        
        // 使用远程控制器关闭客厅灯
        remote.setCommand(livingRoomLightOff);
        remote.pressButton();
        
        // 使用远程控制器打开厨房灯
        remote.setCommand(kitchenLightOn);
        remote.pressButton();
        
        // 使用远程控制器关闭厨房灯
        remote.setCommand(kitchenLightOff);
        remote.pressButton();
    }
}

输出结果:

客厅 灯已打开
客厅 灯已关闭
厨房 灯已打开
厨房 灯已关闭

5.2 家电控制示例

我们可以扩展上面的例子,添加更多种类的家电控制:

// 音响系统接收者
public class StereoSystem {
   
    private String location;
    
    public StereoSystem(String location) {
   
        this.location = location;
    }
    
    public void on() {
   
        System.out.println(location + " 音响已打开");
    }
    
    public void off() {
   
        System.out.println(location + " 音响已关闭");
    }
    
    public void setCD() {
   
        System.out.println(location + " 音响已设置为CD播放模式");
    }
    
    public void setVolume(int volume) {
   
        System.out.println(location + " 音响音量已设置为 " + volume);
    }
}

// 电风扇接收者
public class Fan {
   
    private String location;
    
    public Fan(String location) {
   
        this.location = location;
    }
    
    public void on() {
   
        System.out.println(location + " 电风扇已打开");
    }
    
    public void off() {
   
        System.out.println(location + " 电风扇已关闭");
    }
    
    public void setHigh() {
   
        System.out.println(location + " 电风扇已设置为高速");
    }
    
    public void setMedium() {
   
        System.out.println(location + " 电风扇已设置为中速");
    }
    
    public void setLow() {
   
        System.out.println(location + " 电风扇已设置为低速");
    }
}

然后,为这些家电创建对应的命令:

// 打开音响的命令
public class StereoOnWithCDCommand implements Command {
   
    private StereoSystem stereo;
    
    public StereoOnWithCDCommand(StereoSystem stereo) {
   
        this.stereo = stereo;
    }
    
    @Override
    public void execute() {
   
        stereo.on();
        stereo.setCD();
        stereo.setVolume(11);
    }
}

// 关闭音响的命令
public class StereoOffCommand implements Command {
   
    private StereoSystem stereo;
    
    public StereoOffCommand(StereoSystem stereo) {
   
        this.stereo = stereo;
    }
    
    @Override
    public void execute() {
   
        stereo.off();
    }
}

// 打开风扇并设置高速的命令
public class FanHighCommand implements Command {
   
    private Fan fan;
    
    public FanHighCommand(Fan fan) {
   
        this.fan = fan;
    }
    
    @Override
    public void execute() {
   
        fan.on();
        fan.setHigh();
    }
}

// 关闭风扇的命令
public class FanOffCommand implements Command {
   
    private Fan fan;
    
    public FanOffCommand(Fan fan) {
   
        this.fan = fan;
    }
    
    @Override
    public void execute() {
   
        fan.off();
    }
}

修改调用者类,支持多个按钮:

// 多按钮遥控器
public class MultiButtonRemote {
   
    private Command[] onCommands;
    private Command[] offCommands;
    
    public MultiButtonRemote(int slotCount) {
   
        onCommands = new Command[slotCount];
        offCommands = new Command[slotCount];
        
        // 初始化所有命令为空命令对象,避免空指针异常
        Command noCommand = new NoCommand(); // NoCommand是一个空实现
        for (int i = 0; i < slotCount; i++) {
   
            onCommands[i] = noCommand;
            offCommands[i] = noCommand;
        }
    }
    
    public void setCommand(int slot, Command onCommand, Command offCommand) {
   
        onCommands[slot] = onCommand;
        offCommands[slot] = offCommand;
    }
    
    public void pressOnButton(int slot) {
   
        onCommands[slot].execute();
    }
    
    public void pressOffButton(int slot) {
   
        offCommands[slot].execute();
    }
}

// 空命令 - 用于初始化,避免空指针异常
public class NoCommand implements Command {
   
    @Override
    public void execute() {
   
        // 什么也不做
    }
}

客户端代码:

public class HomeAutomationDemo {
   
    public static void main(String[] args) {
   
        // 创建接收者
        Light livingRoomLight = new Light("客厅");
        Light kitchenLight = new Light("厨房");
        StereoSystem stereo = new StereoSystem("客厅");
        Fan ceilingFan = new Fan("卧室");
        
        // 创建具体命令
        Command livingRoomLightOn = new LightOnCommand(livingRoomLight);
        Command livingRoomLightOff = new LightOffCommand(livingRoomLight);
        Command kitchenLightOn = new LightOnCommand(kitchenLight);
        Command kitchenLightOff = new LightOffCommand(kitchenLight);
        Command stereoOnWithCD = new StereoOnWithCDCommand(stereo);
        Command stereoOff = new StereoOffCommand(stereo);
        Command fanHigh = new FanHighCommand(ceilingFan);
        Command fanOff = new FanOffCommand(ceilingFan);
        
        // 创建多按钮遥控器
        MultiButtonRemote remote = new MultiButtonRemote(4);
        
        // 设置每个插槽对应的命令
        remote.setCommand(0, livingRoomLightOn, livingRoomLightOff);
        remote.setCommand(1, kitchenLightOn, kitchenLightOff);
        remote.setCommand(2, stereoOnWithCD, stereoOff);
        remote.setCommand(3, fanHigh, fanOff);
        
        // 测试按钮
        System.out.println("------ 按下第1个按钮的开按钮 --
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈凯哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值