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++中有什么实际应用场景?

Figma
Figma

Figma 是一款基于云端的 UI 设计工具,可以在线进行产品原型、设计、评审、交付等工作。

下载

命令模式在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()的实现需要根据具体情况进行调整,通常需要记录命令执行前的状态。此外,撤销/重做功能的实现还需要考虑内存管理,避免内存泄漏。

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

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

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

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

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

1100

2023.10.19

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

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

189

2025.10.17

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

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

1502

2025.12.29

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

18

2026.01.19

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

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

395

2023.07.18

堆和栈区别
堆和栈区别

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

575

2023.08.10

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

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

407

2023.08.14

Python 自然语言处理(NLP)基础与实战
Python 自然语言处理(NLP)基础与实战

本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

10

2026.01.27

拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

109

2026.01.26

热门下载

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

精品课程

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

共94课时 | 7.8万人学习

C 教程
C 教程

共75课时 | 4.2万人学习

C++教程
C++教程

共115课时 | 14.2万人学习

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

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