设计模式-命令模式(Command Pattern)

一、命令模式的说明

命令模式(Command Pattern)是一种行为设计模式,它允许将请求封装成对象,从而使得可以将请求参数化、队列化、并且可以用不同的请求来参数化客户端(调用者)的对象。这个模式也支持可撤销的操作。

命令模式通常包括以下几个角色:

**Command(命令):**定义了执行操作的接口,通常包括执行方法(execute())和可能的撤销方法(undo())。

ConcreteCommand(具体命令): 实现了Command接口,持有执行操作所需的相关信息,包括对接收者对象的引用。

**Invoker(调用者):**请求的发送者,通过命令对象来执行请求。

**Receiver(接收者):**实际执行操作的对象。

二、命令模式的场景

命令模式在实际应用中有很多常见的案例,以下是其中一些常用的情况:

**菜单和按钮操作:**在图形用户界面(GUI)应用程序中,菜单项和按钮通常可以被抽象为命令对象。当用户点击菜单项或按钮时,相应的命令被执行,这样做的好处是可以将用户操作与具体的执行操作解耦。

**多级撤销(Undo)操作:**命令模式支持撤销操作,因此它在需要实现撤销多个步骤的应用程序中很有用。每个命令对象可以保存执行操作的状态,以便在撤销时恢复到先前的状态。

**任务调度器:**命令模式可以用于实现任务调度器,其中每个任务可以被封装成一个命令对象,并且可以按照一定的顺序执行。

**日志记录:**命令模式可以用于实现日志记录系统,每个命令对象的执行都可以被记录下来,从而实现日志记录功能。

**遥控器和家电控制:**像前面示例中的遥控器一样,命令模式常用于实现遥控器和家电的控制系统。每个按钮可以关联一个命令对象,当按下按钮时,执行相应的命令。

**数据库事务处理:**在数据库操作中,命令模式可以用于实现事务处理,每个数据库操作可以被封装成一个命令对象,事务的提交或回滚可以看作是对一系列命令对象的执行或撤销。

三、命令模式的优缺点

优点:

**解耦调用者和接收者:**命令模式通过将请求封装成独立的命令对象,从而解耦了请求的发送者和接收者。这使得系统中的对象不需要知道彼此的细节,降低了对象之间的耦合度,提高了系统的灵活性。

**支持撤销和重做:**由于命令对象通常会保存执行所需的状态信息,因此可以很容易地支持撤销和重做操作。这对于实现撤销历史记录、撤销栈等功能非常有用。

**支持命令的排队执行:**命令模式可以将请求排队,并按照一定的顺序执行。这对于实现任务调度器等功能很有用。

**容易扩展:**通过添加新的命令类和接收者类,可以很容易地扩展命令模式,而不需要修改现有的代码。这样使得系统更加灵活和可扩展。

**中心化控制:**命令模式将请求封装成对象,使得可以在系统中集中控制命令的执行。这样可以更好地管理和维护系统的行为。

缺点:

**类爆炸:**如果系统中有大量的命令类和接收者类,可能会导致类的数量急剧增加,从而增加了系统的复杂性。

**可能引入过多的代码:**在某些情况下,引入命令模式可能会增加过多的代码量,特别是对于简单的功能而言,直接调用函数可能更加简单和直接。

**增加了系统的复杂性:**命令模式增加了系统中的额外的抽象层次,可能会增加系统的理解和维护成本。

**不适用于所有情况:**命令模式并不适用于所有的情况,特别是对于简单的功能而言,引入命令模式可能会显得过于复杂。

**可能降低执行效率:**由于命令模式需要将请求封装成对象,可能会导致额外的性能开销,特别是在系统需要频繁创建和销毁命令对象的情况下。

四、命令模式的代码

cpp 复制代码
#include <iostream>
#include <string>
#include <memory>

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

// Receiver
class Light {
public:
    void turnOn() {
        std::cout << "Light is on\n";
    }

    void turnOff() {
        std::cout << "Light is off\n";
    }
};

// Concrete Command
class TurnOnCommand : public Command {
public:
    TurnOnCommand(std::shared_ptr<Light> light) : m_light(light) {}
    void execute() override {
        m_light->turnOn();
    }
private:
    std::shared_ptr<Light> m_light;
};

class TurnOffCommand : public Command {
public:
    TurnOffCommand(std::shared_ptr<Light> light) : m_light(light) {}
    void execute() override {
        m_light->turnOff();
    }
private:
    std::shared_ptr<Light> m_light;
};

// Invoker
class RemoteControl {
public:
    void setCommand(std::shared_ptr<Command> command) {
        m_command = command;
    }

    void pressButton() {
        m_command->execute();
    }

private:
    std::shared_ptr<Command> m_command;
};

int main() {
    // Receiver
    std::shared_ptr<Light> light = std::make_shared<Light>();

    // Concrete Commands
    std::shared_ptr<Command> turnOnCommand = std::make_shared<TurnOnCommand>(light);
    std::shared_ptr<Command> turnOffCommand = std::make_shared<TurnOffCommand>(light);

    // Invoker
    RemoteControl remote;

    // Set commands
    remote.setCommand(turnOnCommand);
    remote.pressButton(); // Output: Light is on

    remote.setCommand(turnOffCommand);
    remote.pressButton(); // Output: Light is off

    return 0;
}
相关推荐
LXS_3577 小时前
Day 18 C++提高 之 STL常用容器(string、vector、deque)
开发语言·c++·笔记·学习方法·改行学it
deng-c-f8 小时前
Linux C/C++ 学习日记(53):原子操作(二):实现shared_ptr
开发语言·c++·学习
一个不知名程序员www8 小时前
算法学习入门---结构体和类(C++)
c++·算法
墨雪不会编程9 小时前
C++ string 详解:STL 字符串容器的使用技巧
java·开发语言·c++
yangpipi-10 小时前
《C++并发编程实战》第5章 C++内存模型和原子操作
android·java·c++
SunkingYang10 小时前
MFC进程间消息通信深度解析:SendMessage、PostMessage与SendNotifyMessage的底层实现与实战指南
c++·mfc·共享内存·通信·postmessage·sendmessage·进程间
XFF不秃头11 小时前
力扣刷题笔记-旋转图像
c++·笔记·算法·leetcode
王老师青少年编程11 小时前
csp信奥赛C++标准模板库STL案例应用3
c++·算法·stl·csp·信奥赛·lower_bound·标准模版库
Tim_1012 小时前
【C++入门】04、C++浮点型
开发语言·c++
hkNaruto12 小时前
【C++】记录一次C++程序编译缓慢原因分析——滥用stdafx.h公共头文件
开发语言·c++