跳转到内容

C++ 命令模式实现

来自代码酷

C++命令模式实现[编辑 | 编辑源代码]

命令模式(Command Pattern)是一种行为设计模式,它将请求或操作封装为独立的对象,从而使你可以参数化客户端与不同的请求、队列或日志请求,并支持可撤销的操作。在C++中,命令模式常用于实现回调机制、任务队列或撤销/重做功能。

介绍[编辑 | 编辑源代码]

命令模式的核心思想是将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化。这种模式的主要组成部分包括:

  • 命令接口(Command):声明执行操作的接口。
  • 具体命令(ConcreteCommand):实现命令接口,绑定接收者与动作。
  • 接收者(Receiver):知道如何执行与请求相关的操作。
  • 调用者(Invoker):触发命令对象执行请求。
  • 客户端(Client):创建具体的命令对象并设置其接收者。

命令模式的主要优点包括:

  • 解耦调用操作的对象与知道如何实现操作的对象。
  • 支持撤销和重做操作。
  • 支持将命令组合成复合命令(宏命令)。

代码示例[编辑 | 编辑源代码]

以下是一个简单的C++实现示例,展示如何使用命令模式控制电器的开关:

#include <iostream>
#include <memory>
#include <vector>

// 接收者类:电器
class ElectronicDevice {
public:
    void turnOn() {
        std::cout << "Device is ON" << std::endl;
    }
    void turnOff() {
        std::cout << "Device is OFF" << std::endl;
    }
};

// 命令接口
class Command {
public:
    virtual ~Command() = default;
    virtual void execute() = 0;
};

// 具体命令:打开电器
class TurnOnCommand : public Command {
    ElectronicDevice& device;
public:
    explicit TurnOnCommand(ElectronicDevice& dev) : device(dev) {}
    void execute() override {
        device.turnOn();
    }
};

// 具体命令:关闭电器
class TurnOffCommand : public Command {
    ElectronicDevice& device;
public:
    explicit TurnOffCommand(ElectronicDevice& dev) : device(dev) {}
    void execute() override {
        device.turnOff();
    }
};

// 调用者:遥控器
class RemoteControl {
    std::vector<std::unique_ptr<Command>> commands;
public:
    void addCommand(std::unique_ptr<Command> cmd) {
        commands.push_back(std::move(cmd));
    }
    void pressButton(int index) {
        if (index >= 0 && index < commands.size()) {
            commands[index]->execute();
        }
    }
};

int main() {
    ElectronicDevice tv;
    RemoteControl remote;

    // 设置命令
    remote.addCommand(std::make_unique<TurnOnCommand>(tv));
    remote.addCommand(std::make_unique<TurnOffCommand>(tv));

    // 执行命令
    remote.pressButton(0); // 输出: Device is ON
    remote.pressButton(1); // 输出: Device is OFF

    return 0;
}

输出[编辑 | 编辑源代码]

Device is ON
Device is OFF

类图[编辑 | 编辑源代码]

以下是用mermaid绘制的命令模式类图:

classDiagram class Command { <<interface>> +execute() } class ConcreteCommandA { -receiver: Receiver +execute() } class ConcreteCommandB { -receiver: Receiver +execute() } class Receiver { +action() } class Invoker { -command: Command +setCommand() +executeCommand() } class Client Command <|-- ConcreteCommandA Command <|-- ConcreteCommandB ConcreteCommandA --> Receiver ConcreteCommandB --> Receiver Invoker o-- Command Client ..> ConcreteCommandA Client ..> ConcreteCommandB Client ..> Receiver Client ..> Invoker

实际应用场景[编辑 | 编辑源代码]

命令模式在以下场景中特别有用: 1. GUI按钮和菜单项:每个按钮点击或菜单选择可以绑定到不同的命令对象。 2. 事务系统:每个操作可以封装为命令,支持撤销和重做。 3. 任务调度:将任务封装为命令对象,放入队列中按顺序执行。 4. 宏录制:将多个命令组合成一个复合命令。

高级应用:支持撤销[编辑 | 编辑源代码]

扩展前面的例子,添加撤销功能:

// 扩展命令接口支持撤销
class UndoableCommand : public Command {
public:
    virtual void undo() = 0;
};

// 具体命令:带撤销的开关命令
class ToggleCommand : public UndoableCommand {
    ElectronicDevice& device;
    bool wasOn = false;
public:
    explicit ToggleCommand(ElectronicDevice& dev) : device(dev) {}
    void execute() override {
        wasOn = !wasOn;
        if (wasOn) device.turnOn();
        else device.turnOff();
    }
    void undo() override {
        wasOn = !wasOn;
        if (wasOn) device.turnOn();
        else device.turnOff();
    }
};

// 扩展调用者支持撤销
class AdvancedRemoteControl {
    std::vector<std::unique_ptr<UndoableCommand>> commands;
    std::vector<std::unique_ptr<UndoableCommand>> history;
public:
    void addCommand(std::unique_ptr<UndoableCommand> cmd) {
        commands.push_back(std::move(cmd));
    }
    void pressButton(int index) {
        if (index >= 0 && index < commands.size()) {
            commands[index]->execute();
            history.push_back(std::move(commands[index]));
            commands.erase(commands.begin() + index);
        }
    }
    void undoLast() {
        if (!history.empty()) {
            history.back()->undo();
            history.pop_back();
        }
    }
};

数学表示[编辑 | 编辑源代码]

命令模式可以形式化表示为: {Commandexecute()ConcreteCommandexecute()=receiver.action()InvokersetCommand(c:Command),executeCommand()=c.execute()

总结[编辑 | 编辑源代码]

命令模式在C++中提供了一种灵活的方式来封装操作请求,使系统更易于扩展和维护。通过将请求封装为对象,你可以:

  • 参数化对象与不同请求
  • 支持队列请求
  • 实现撤销/重做功能
  • 构建复合命令(宏命令)

这种模式特别适合需要解耦发送者和接收者、或者需要支持事务性操作的场景。对于C++开发者来说,结合智能指针和现代C++特性可以创建更安全、更高效的命令模式实现。