✅作者简介:大家好,我是 Meteors., 向往着更加简洁高效的代码写法与编程方式,持续分享Java技术内容。
🍎个人主页:Meteors.的博客
💞当前专栏:设计模式
✨特色专栏:知识分享
🥭本文内容:23种设计模式——命令模式(Command Pattern)
📚 ** ps **  :阅读文章如果有问题或者疑惑,欢迎在评论区提问或指出。


目录

一. 背景

二. 介绍

三. 核心概念

四. 代码示例

五. 使用场景

六. 总结


一. 背景

说到命令模式,可能很多人会想到Windows或者Mac的命令行。其实它们的关联并不大,因为命令行界面是一个​​人机交互系统。的工作原理更多是基于​​字符串解析 + 程序调用(如 shell 脚本、可执行程序)​​,而不是基于面向对象设计模式中的“命令对象封装”。​​也没有明确的 Command、Invoker、Receiver 对象模型。下面我将会像你介绍设计模式中的命令模式。


二. 介绍

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


三. 核心概念

命令模式的核心思想是将"请求"封装成对象,将发出命令的责任和执行命令的责任分割开,委派给不同的对象。这种模式通过解耦发送者和接收者来实现更灵活的设计。
在命令模式中,通常包含以下角色:

  • 命令接口(Command):声明执行操作的接口
  • 具体命令(ConcreteCommand):实现命令接口,持有接收者对象的引用
  • 接收者(Receiver):执行具体业务逻辑的对象
  • 调用者(Invoker):负责调用命令对象执行请求
  • 客户端(Client):创建具体命令对象并设置其接收者

四. 代码示例

下面是一个开始和取消命令的实现。它和策略模式很像,但它最大的不同是,它将实际执行的代码都统一到了接收者 。

// 命令接口
public interface Command {
    void execute(); // 执行命令
    void undo();    // 撤销命令(可选)
}
// 接收者:电灯
public class Light {
    private String location;
    
    public Light(String location) {
        this.location = location;
    }
    
    public void on() {
        System.out.println("💡 " + location + " 电灯已打开");
    }
    
    public void off() {
        System.out.println("💡 " + location + " 电灯已关闭");
    }
}

// 接收者:空调
public class AirConditioner {
    private int temperature = 26;
    
    public void on() {
        System.out.println("❄️ 空调已开启");
    }
    
    public void off() {
        System.out.println("❄️ 空调已关闭");
    }
    
    public void setTemperature(int temp) {
        this.temperature = temp;
        System.out.println("❄️ 空调温度设置为 " + temp + "°C");
    }
    
    public int getTemperature() {
        return temperature;
    }
}

// 接收者:电视
public class Television {
    private int channel = 1;
    private int volume = 20;
    
    public void on() {
        System.out.println("📺 电视已开启");
    }
    
    public void off() {
        System.out.println("📺 电视已关闭");
    }
    
    public void setChannel(int channel) {
        this.channel = channel;
        System.out.println("📺 切换到频道 " + channel);
    }
    
    public void setVolume(int volume) {
        this.volume = volume;
        System.out.println("📺 音量设置为 " + volume);
    }
}

// 具体命令:开灯命令
public class LightOnCommand implements Command {
    private Light light;
    
    public LightOnCommand(Light light) {
        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) {
        this.light = light;
    }
    
    @Override
    public void execute() {
        light.off();
    }
    
    @Override
    public void undo() {
        light.on();
    }
}

// 具体命令:开空调命令
public class AirConditionerOnCommand implements Command {
    private AirConditioner ac;
    
    public AirConditionerOnCommand(AirConditioner ac) {
        this.ac = ac;
    }
    
    @Override
    public void execute() {
        ac.on();
        ac.setTemperature(24);
    }
    
    @Override
    public void undo() {
        ac.off();
    }
}

// 具体命令:设置空调温度
public class AirConditionerTempCommand implements Command {
    private AirConditioner ac;
    private int prevTemp;
    private int newTemp;
    
    public AirConditionerTempCommand(AirConditioner ac, int newTemp) {
        this.ac = ac;
        this.newTemp = newTemp;
    }
    
    @Override
    public void execute() {
        prevTemp = ac.getTemperature();
        ac.setTemperature(newTemp);
    }
    
    @Override
    public void undo() {
        ac.setTemperature(prevTemp);
    }
}

// 具体命令:开电视命令
public class TVOnCommand implements Command {
    private Television tv;
    
    public TVOnCommand(Television tv) {
        this.tv = tv;
    }
    
    @Override
    public void execute() {
        tv.on();
        tv.setChannel(5);
        tv.setVolume(30);
    }
    
    @Override
    public void undo() {
        tv.off();
    }
}

// 空命令(避免空指针)
public class NoCommand implements Command {
    @Override
    public void execute() {
        // 什么都不做
    }
    
    @Override
    public void undo() {
        // 什么都不做
    }
}

import java.util.Stack;

// 调用者:智能遥控器
public class RemoteControl {
    private Command[] onCommands;      // 开按钮命令数组
    private Command[] offCommands;     // 关按钮命令数组
    private Stack<Command> undoStack;  // 撤销栈,记录执行过的命令
    
    public RemoteControl() {
        onCommands = new Command[5];
        offCommands = new Command[5];
        undoStack = new Stack<>();
        
        // 初始化为空命令
        Command noCommand = new NoCommand();
        for (int i = 0; i < 5; 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();
        undoStack.push(onCommands[slot]); // 记录可撤销的命令
    }
    
    // 按下关按钮
    public void pressOffButton(int slot) {
        offCommands[slot].execute();
        undoStack.push(offCommands[slot]); // 记录可撤销的命令
    }
    
    // 撤销按钮
    public void pressUndoButton() {
        if (!undoStack.isEmpty()) {
            Command command = undoStack.pop();
            command.undo();
        } else {
            System.out.println("⚠️ 没有可撤销的操作");
        }
    }
    
    // 显示遥控器配置
    public void display() {
        System.out.println("\n===== 遥控器配置 =====");
        for (int i = 0; i < onCommands.length; i++) {
            System.out.println("插槽 " + i + ": " + 
                onCommands[i].getClass().getSimpleName() + " / " + 
                offCommands[i].getClass().getSimpleName());
        }
    }
}

import java.util.Arrays;

// 宏命令:执行一组命令
public class MacroCommand implements Command {
    private Command[] commands;
    
    public MacroCommand(Command... commands) {
        this.commands = commands;
    }
    
    @Override
    public void execute() {
        System.out.println("🔵 执行宏命令开始...");
        for (Command command : commands) {
            command.execute();
        }
        System.out.println("🔵 宏命令执行完成");
    }
    
    @Override
    public void undo() {
        System.out.println("🔵 撤销宏命令...");
        // 反向撤销
        for (int i = commands.length - 1; i >= 0; i--) {
            commands[i].undo();
        }
    }
}

public class CommandPatternDemo {
    public static void main(String[] args) {
        // 创建接收者(家电)
        Light livingRoomLight = new Light("客厅");
        Light kitchenLight = new Light("厨房");
        AirConditioner ac = new AirConditioner();
        Television tv = new Television();
        
        // 创建命令对象
        Command livingRoomLightOn = new LightOnCommand(livingRoomLight);
        Command livingRoomLightOff = new LightOffCommand(livingRoomLight);
        Command kitchenLightOn = new LightOnCommand(kitchenLight);
        Command kitchenLightOff = new LightOffCommand(kitchenLight);
        Command acOn = new AirConditionerOnCommand(ac);
        Command acOff = new AirConditionerOffCommand(ac);
        Command acTemp = new AirConditionerTempCommand(ac, 22);
        Command tvOn = new TVOnCommand(tv);
        Command tvOff = new TVOffCommand(tv);
        
        // 创建遥控器并设置命令
        RemoteControl remote = new RemoteControl();
        remote.setCommand(0, livingRoomLightOn, livingRoomLightOff);
        remote.setCommand(1, kitchenLightOn, kitchenLightOff);
        remote.setCommand(2, acOn, acOff);
        remote.setCommand(3, tvOn, tvOff);
        
        remote.display();
        
        System.out.println("\n===== 基础操作测试 =====");
        
        // 测试开灯
        remote.pressOnButton(0);
        remote.pressOffButton(0);
        remote.pressUndoButton(); // 撤销关灯,灯又亮了
        
        System.out.println("\n" + "-".repeat(50));
        
        // 测试空调
        remote.pressOnButton(2);
        remote.pressOnButton(2); // 调温度
        remote.pressUndoButton(); // 撤销调温度
        
        System.out.println("\n" + "-".repeat(50));
        
        System.out.println("\n===== 宏命令测试(一键场景)=====");
        
        // 创建回家模式宏命令(开客厅灯+开空调)
        Command homeMode = new MacroCommand(livingRoomLightOn, acOn);
        remote.setCommand(4, homeMode, homeMode); // 用同一个宏命令
        
        remote.pressOnButton(4); // 执行回家模式
        remote.pressUndoButton(); // 撤销回家模式
        
        System.out.println("\n" + "-".repeat(50));
        
        System.out.println("\n===== 命令队列模拟(日志记录)=====");
        
        // 模拟命令队列执行
        List<Command> commandQueue = Arrays.asList(
            kitchenLightOn,
            tvOn,
            acTemp
        );
        
        // 记录日志(实际应用中可序列化到文件)
        System.out.println("📋 执行命令队列(可持久化日志):");
        for (Command cmd : commandQueue) {
            System.out.println("  执行: " + cmd.getClass().getSimpleName());
            cmd.execute();
        }
    }
}


五. 使用场景

命令模式用于以下场景:

  • 需要将请求调用者和请求接收者解耦
  • 需要支持撤销操作
  • 需要支持队列操作
  • 需要记录操作日志
  • 需要支持事务操作

六. 总结

命令模式的主要优点是降低了系统组件之间的耦合度,使得系统更加灵活和易于维护。但同时也要注意,过多的命令类可能会增加系统的复杂性,因此在使用时需要权衡利弊。


最后,

        其它设计模式会陆续更新,希望文章对你有所帮助!

更多推荐