命令模式——C++实现

1. 命令模式简介

命令模式 是一种行为型模式
**命令模式的定义:**将请求封装成一个对象,使发出请求的责任和执行请求的责任分开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理

命令模式的意思就是将请求的调用者和请求的接受者(或者叫执行者)分开,将他们解耦。

打个比方,以饭店吃饭为例,我点了个地三鲜,"做一盘地三鲜"就是一个请求,"我"就是请求的调用者,"大厨"就是请求的执行者。

命令模式就是将请求封装成了一个类对象,这个类对象包含了请求的接受者(也就是执行者),以及接受者需要执行的操作,并且这个类对象对外只暴露出一个execute的接口,(很多时候也会增加一个redo接口,来实现命令的撤销)。

无论是谁拿到了这个类对象,都可以通过调用execute接口来完成这个请求,而无需知道请求是如何完成的,以及请求是由谁完成的。

命令模式通过封装请求,可以实现请求的传递、延迟调用、命令的撤销、重做等功能。

核心的概念已经讲清楚了,下面看代码演示。

2. C++代码演示

代码演示以一个万能遥控器为例子。

有一些家用电器,每个家用电器的打开方式不同,并且打开的接口名称也不同。

需要实现一个万能遥控器,这个万能遥控器有一定数量的插槽。每一个插槽可以控制一个家用电器,并且每个插槽都有开、关两个按钮。

万能遥控器还有一个undo、一个redo按钮,实现撤销上一个命令,以及重做上一个命令。

将家用电器的打开请求封装成命令对象,并且对外暴露出一个execute接口、一个undo接口、一个redo接口。就可以将命令对象插入到万能遥控器的插槽上,遥控器只知道命令对象上有execute接口即可,无需知道怎样驱动具体的电器如何工作。

无论将来新增加了何种的电器,只需要实现对应的命令对象,万能遥控器即可使用该电器。

如果不太理解,请仔细看代码的实现:

cpp 复制代码
#include <iostream>
#include <vector>
#include <memory>
#include <stack>
#include <deque>
using namespace std;

class Light
{
public:
    void turnOn()
    {
        cout << "Light turned on" << endl;
    }

    void turnOff()
    {
        cout << "Light turned off" << endl;
    }
};

class Fan
{
public:
    enum Speed { OFF,LOW, MEDIUM, HIGH };
    void turnOn(Speed speed)
    {
        this->speed = speed;
        cout << "Fan turned on at " << speed << " speed" << endl;
    }
    void turnOff()
    {
        cout << "Fan turned off" << endl;
    }
    Speed getSpeed()const {
        return speed;
    }
private:
    Speed speed;
};

class Command {
public:
    virtual void execute() = 0;
    virtual void undo() = 0;
};

class TurnOnLightCommand : public Command {
private:
    Light* light = nullptr;
public:
    TurnOnLightCommand(Light* light) {
        this->light = light;
    }
    void execute() {
        light->turnOn();
    }
    void undo() {
        light->turnOff();
    }
};

class TurnOffLightCommand : public Command {
private:
    Light* light = nullptr;
public:
    TurnOffLightCommand(Light* light) {
        this->light = light;
    }
    void execute() {
        light->turnOff();
    }
    void undo() {
        light->turnOn();
    }
};

class TurnOnFanCommand : public Command {
private:
    Fan* fan = nullptr;
    Fan::Speed speed = Fan::LOW;
public:
    TurnOnFanCommand(Fan* fan, Fan::Speed speed = Fan::LOW) {
        this->fan = fan;
    }
    void execute() {
        this->speed = speed;
        fan->turnOn(speed);
    }
    void undo() {
        fan->turnOff();
    }
};

class TurnOffFanCommand : public Command {
private:
    Fan* fan = nullptr;
    Fan::Speed speed = Fan::OFF;
public:
    TurnOffFanCommand(Fan* fan) {
        this->fan = fan;
    }
    void execute() {
        speed = fan->getSpeed();
        fan->turnOff();
    }
    void undo() {
        fan->turnOn(speed);
    }
};

class NoCommand : public Command {
public:
    void execute() {}
    void undo() {}
};

class RemoteControl
{
public:
    RemoteControl(unsigned int numCommands, unsigned int maxUndoSize = 50) {
        for (unsigned int i = 0; i < numCommands; i++) {
            OnCommands.push_back(shared_ptr<Command>(new NoCommand()));
            OffCommands.push_back(shared_ptr<Command>(new NoCommand()));
        }
        maxUndoSize = maxUndoSize;
    }
    void setCommand(unsigned int slot, Command* onCommand, Command* offCommand) {
        OnCommands[slot] = shared_ptr<Command>(onCommand);
        OffCommands[slot] = shared_ptr<Command>(offCommand);
    }
    void onButtonWasPushed(unsigned int slot) {
        OnCommands[slot]->execute();
        logUndo(OnCommands[slot]);
        clearRedoStack();
    }
    void offButtonWasPushed(unsigned int slot) {
        OffCommands[slot]->execute();
        logUndo(OffCommands[slot]);
        clearRedoStack();
    }
    void undoButtonWasPushed() {
        if (!undoStack.empty()) {
            shared_ptr<Command> command = undoStack.back();
            command->undo();
            logRedo(command);
            undoStack.pop_back();
        }
        else
            cout << "没有可撤销的命令" << endl;
    }
    void redoButtonWasPushed() {
        if (!redoStack.empty()) {
            shared_ptr<Command> command = redoStack.top();
            command->execute();
            logUndo(command);
            redoStack.pop();
        }
        else
            cout << "没有可重做的命令" << endl;
    }
private:
    void logUndo(shared_ptr<Command> command) {
        undoStack.push_back(command);
        if (undoStack.size() > maxUndoSize)
            undoStack.pop_front();
    }
    void logRedo(shared_ptr<Command> command) {
        redoStack.push(command);
    }
    void clearRedoStack() {
        if (!redoStack.empty())
            stack<shared_ptr<Command>>().swap(redoStack);
    }
private:
    vector<shared_ptr<Command>> OnCommands;
    vector<shared_ptr<Command>> OffCommands;
    deque<shared_ptr<Command>> undoStack;
    stack<shared_ptr<Command>> redoStack;
    unsigned int maxUndoSize = 50;
};

void main()
{
    Light* light = new Light();
    Fan* fan = new Fan();
    RemoteControl* remote = new RemoteControl(3); // 遥控器有3个插槽

    // 设置每个插槽的命令
    remote->setCommand(0, new TurnOnLightCommand(light), new TurnOffLightCommand(light));
    remote->setCommand(1, new TurnOnFanCommand(fan), new TurnOffFanCommand(fan));
    remote->setCommand(2, new TurnOnLightCommand(light), new TurnOffLightCommand(light));

    cout << "按下插槽0的打开按钮" << endl;
    remote->onButtonWasPushed(0);

    cout << "---------------------" << endl;
    cout << "按下插槽1的打开按钮" << endl;
    remote->onButtonWasPushed(1);

    cout << "---------------------" << endl;
    cout << "按下插槽1的关闭按钮" << endl;
    remote->offButtonWasPushed(1);

    cout << "---------------------" << endl;
    cout << "按下插槽2的打开按钮" << endl;
    remote->onButtonWasPushed(2);

    cout << "---------------------" << endl;
    cout << "按下撤销按钮" << endl;
    remote->undoButtonWasPushed();

    cout << "---------------------" << endl;
    cout << "按下重做按钮" << endl;
    remote->redoButtonWasPushed();

    cout << "---------------------" << endl;
    cout << "按下重做按钮" << endl;
    remote->redoButtonWasPushed();

    

    delete remote;
    delete light;
    delete fan;
}

下面是执行结果:

以上就是对命令模式的讲解,如果不太理解或者有讲错的地方欢迎在评论区批评指正!

相关推荐
arong_xu1 小时前
C++23 格式化输出新特性详解: std::print 和 std::println
开发语言·c++·c++23
冷雨夜中漫步2 小时前
领域驱动设计(4)—绑定模型与实现
java·开发语言·笔记·后端·设计模式
JINGWHALE16 小时前
设计模式 结构型 外观模式(Facade Pattern)与 常见技术框架应用 解析
前端·人工智能·后端·设计模式·性能优化·系统架构·外观模式
玉带湖水位记录员6 小时前
外观模式——C++实现
c++·外观模式
zhonguncle8 小时前
「C++笔记」vector:C++中的新式“数组”
c++
❦丿多像灬笑话、℡9 小时前
leetcode热题100(763. 划分字母区间) c++
c++·算法·leetcode
JINGWHALE19 小时前
设计模式 结构型 代理模式(Proxy Pattern)与 常见技术框架应用 解析
前端·人工智能·后端·设计模式·性能优化·系统架构·代理模式
泰山小张只吃荷园10 小时前
软件体系结构、设计模式、课程期末复习知识点全总结-SCAU
网络·数据库·sql·计算机网络·设计模式·sqlserver
angen201810 小时前
二十三种设计模式-抽象工厂模式
设计模式·抽象工厂模式
Tiandaren10 小时前
医学图像分析工具01:FreeSurfer || Recon -all 全流程MRI皮质表面重建
c++·图像处理·python·深度学习·数据挖掘·数据分析·健康医疗