0

0

C++如何实现命令模式 C++命令模式的设计与示例

冰火之心

冰火之心

发布时间:2025-06-26 12:16:01

|

537人浏览过

|

来源于php中文网

原创

命令模式封装请求以解耦发送者与接收者,策略模式封装算法以实现运行时替换。命令模式的核心在于将请求封装为对象,使能支持撤销、日志、排队等功能,主要涉及command、concretecommand、receiver、invoker和client五个角色;而策略模式通过封装不同的算法族,允许算法独立变化并可在运行时切换,核心在于算法的可替换性。两者虽均基于接口设计思想,但应用场景不同:命令模式适用于gui操作、事务处理、游戏动作记录等需保存或撤销请求的场景,策略模式则适用于支付方式、排序算法等需动态切换行为的场景。

C++如何实现命令模式 C++命令模式的设计与示例

C++命令模式的核心在于将请求封装成一个对象,从而允许你参数化客户端对象,支持请求排队、记录请求日志,以及支持可撤销的操作。简单来说,就是把“做什么”和“谁去做”解耦。

C++如何实现命令模式 C++命令模式的设计与示例

解决方案

C++如何实现命令模式 C++命令模式的设计与示例

命令模式涉及几个关键角色:

立即学习C++免费学习笔记(深入)”;

C++如何实现命令模式 C++命令模式的设计与示例
  • Command(命令接口): 声明执行操作的接口。
  • ConcreteCommand(具体命令): 将一个接收者对象绑定于一个动作。调用接收者相应的操作,以实现 Execute。
  • Receiver(接收者): 知道如何实施与执行一个请求相关的操作。任何类都可以作为接收者。
  • Invoker(调用者): 要求命令执行请求。
  • Client(客户端): 创建 ConcreteCommand 对象并设置其接收者。

以下是一个简单的C++命令模式示例:

#include 
#include 

// Receiver
class Light {
public:
    void turnOn() {
        std::cout << "Light is ON" << std::endl;
    }

    void turnOff() {
        std::cout << "Light is OFF" << std::endl;
    }
};

// Command Interface
class Command {
public:
    virtual void execute() = 0;
    virtual ~Command() {}
};

// Concrete Command
class TurnOnCommand : public Command {
private:
    Light* light;

public:
    TurnOnCommand(Light* light) : light(light) {}

    void execute() override {
        light->turnOn();
    }
};

// Concrete Command
class TurnOffCommand : public Command {
private:
    Light* light;

public:
    TurnOffCommand(Light* light) : light(light) {}

    void execute() override {
        light->turnOff();
    }
};

// Invoker
class RemoteControl {
private:
    std::vector commands;

public:
    void setCommand(Command* command) {
        commands.push_back(command);
    }

    void pressButton() {
        if (!commands.empty()) {
            commands.back()->execute();
            commands.pop_back(); // 执行后移除,简化示例
        } else {
            std::cout << "No command set" << std::endl;
        }
    }
};

int main() {
    Light* livingRoomLight = new Light();

    TurnOnCommand* turnOnCmd = new TurnOnCommand(livingRoomLight);
    TurnOffCommand* turnOffCmd = new TurnOffCommand(livingRoomLight);

    RemoteControl* remote = new RemoteControl();
    remote->setCommand(turnOnCmd);
    remote->setCommand(turnOffCmd);

    remote->pressButton(); // Light is OFF (因为后设置的是TurnOffCommand)
    remote->pressButton(); // Light is ON

    delete turnOnCmd;
    delete turnOffCmd;
    delete livingRoomLight;
    delete remote;

    return 0;
}

这个例子中,Light是接收者,TurnOnCommandTurnOffCommand是具体命令,RemoteControl是调用者。 客户端负责创建命令并将它们传递给调用者。

命令模式在C++中有什么实际应用场景?

蝉妈妈AI
蝉妈妈AI

电商人专属的AI营销助手

下载

命令模式在GUI应用程序、事务处理、宏记录、以及游戏开发中都有广泛应用。例如,在文本编辑器中,每个操作(如复制、粘贴、删除)都可以封装成一个命令对象。这样做的好处是,可以很容易地实现撤销/重做功能,只需要维护一个命令历史记录即可。此外,命令模式还可以用于实现复杂的事务处理,确保一系列操作要么全部成功执行,要么全部回滚。 在游戏开发中,玩家的每一个操作(如移动、攻击)都可以视为一个命令,便于记录和回放。

C++中如何实现命令的撤销(Undo)和重做(Redo)?

实现撤销和重做功能,需要在Command接口中添加undo()方法,并在ConcreteCommand中实现该方法。同时,需要维护一个命令历史栈,用于记录已执行的命令。

// Command Interface (with Undo)
class Command {
public:
    virtual void execute() = 0;
    virtual void undo() = 0; // 添加 undo 方法
    virtual ~Command() {}
};

// Concrete Command (with Undo)
class TurnOnCommand : public Command {
private:
    Light* light;
    bool previousState; // 记录之前的状态,以便 undo

public:
    TurnOnCommand(Light* light) : light(light), previousState(false) {}

    void execute() override {
        previousState = (/*假设Light有个getState()方法*/ false); // 实际应用中需要获取灯的当前状态
        light->turnOn();
    }

    void undo() override {
        if (previousState) {
            light->turnOn(); // 恢复到之前的状态(如果之前是开着的)
        } else {
            light->turnOff(); // 恢复到之前的状态(如果之前是关着的)
        }
    }
};

//Invoker (with Undo/Redo)
class RemoteControl {
private:
    std::vector commandHistory;
    int currentCommandIndex = -1; // 指向当前执行的命令

public:
    void executeCommand(Command* command) {
        command->execute();
        if (currentCommandIndex < (int)commandHistory.size() - 1) {
            // 如果执行了undo之后的新命令,则清除后面的历史
            commandHistory.erase(commandHistory.begin() + currentCommandIndex + 1, commandHistory.end());
        }
        commandHistory.push_back(command);
        currentCommandIndex++;
    }

    void undo() {
        if (currentCommandIndex >= 0) {
            commandHistory[currentCommandIndex]->undo();
            currentCommandIndex--;
        }
    }

    void redo() {
        if (currentCommandIndex < (int)commandHistory.size() - 1) {
            currentCommandIndex++;
            commandHistory[currentCommandIndex]->execute();
        }
    }
};

int main() {
    Light* livingRoomLight = new Light();
    RemoteControl* remote = new RemoteControl();

    TurnOnCommand* turnOnCmd = new TurnOnCommand(livingRoomLight);
    TurnOffCommand* turnOffCmd = new TurnOffCommand(livingRoomLight);

    remote->executeCommand(turnOnCmd); // Light is ON
    remote->executeCommand(turnOffCmd); // Light is OFF

    remote->undo(); // Light is ON
    remote->undo(); // Light is OFF

    remote->redo(); // Light is ON
    remote->redo(); // Light is OFF

    delete turnOnCmd;
    delete turnOffCmd;
    delete livingRoomLight;
    delete remote;

    return 0;
}

注意,undo()的实现需要根据具体情况进行调整,通常需要记录命令执行前的状态。此外,撤销/重做功能的实现还需要考虑内存管理,避免内存泄漏。

命令模式和策略模式有什么区别

虽然命令模式和策略模式都涉及到封装,但它们的目的不同。命令模式封装的是请求,而策略模式封装的是算法。 命令模式的重点在于解耦请求的发送者和接收者,允许请求排队、记录日志等。 策略模式的重点在于提供一种在运行时选择算法的方式,使得算法可以独立于使用它的客户端而变化。 策略模式关注的是算法的可替换性,而命令模式关注的是请求的封装和执行。 简单来说,策略模式解决的是“用哪个算法”,命令模式解决的是“做什么操作”。

相关专题

更多
硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

991

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

51

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

234

2025.12.29

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

371

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

563

2023.08.10

页面置换算法
页面置换算法

页面置换算法是操作系统中用来决定在内存中哪些页面应该被换出以便为新的页面提供空间的算法。本专题为大家提供页面置换算法的相关文章,大家可以免费体验。

389

2023.08.14

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

65

2025.12.31

php网站源码教程大全
php网站源码教程大全

本专题整合了php网站源码相关教程,阅读专题下面的文章了解更多详细内容。

43

2025.12.31

视频文件格式
视频文件格式

本专题整合了视频文件格式相关内容,阅读专题下面的文章了解更多详细内容。

35

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 5.8万人学习

C 教程
C 教程

共75课时 | 3.8万人学习

C++教程
C++教程

共115课时 | 10.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号