行为型模式:②命令模式(Command Pattern)

行为型模式:②命令模式(Command Pattern)

核心思想

将请求封装为独立对象,该对象包含执行请求所需的所有信息(接收者、操作、参数),从而实现:
解耦请求的「发送者」(如遥控器)和「接收者」(如家电):发送者无需知道接收者如何执行请求,仅需触发命令;
灵活管理请求:支持请求的队列化、延迟执行、撤销(Undo)、重做(Redo);
扩展新请求无需修改现有发送者和接收者,符合「开闭原则」。

核心本质

请求 = 对象,将 “做什么”(动作)和 “谁来做”(接收者)封装为命令对象,使请求的生命周期可管理、可扩展。

典型场景

遥控器控制家电(开灯、关灯、调音量);
文本编辑器的撤销 / 重做功能;
任务调度系统(队列化执行多个任务);
接口请求的日志记录与重试(命令队列 + 执行日志)。

C语言编写

场景示例

家电控制系统:
接收者(Receiver):灯(Light,支持开关)、音响(Audio,支持音量调节);
抽象命令(Command):定义 execute(执行)、undo(撤销)接口;
具体命令(ConcreteCommand):开灯、关灯、调大音量、调小音量(绑定接收者和具体操作);
调用者(Invoker):遥控器(RemoteControl),管理命令队列,支持执行所有命令、撤销最后一个命令。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 最大命令队列长度
#define MAX_CMD_QUEUE 10
// 最大设备名称长度
#define MAX_DEV_NAME 32

// -------------------------- 1. 接收者(Receiver):实际执行操作的设备 --------------------------
// 接收者1:灯(支持开关)
typedef struct Light {
    char name[MAX_DEV_NAME];
    int is_on; // 状态:0=关,1=开
    void (*turn_on)(struct Light* self);
    void (*turn_off)(struct Light* self);
} Light;

void light_turn_on(Light* self) {
    self->is_on = 1;
    printf("[%s] 开灯成功(当前状态:开启)\n", self->name);
}

void light_turn_off(Light* self) {
    self->is_on = 0;
    printf("[%s] 关灯成功(当前状态:关闭)\n", self->name);
}

Light* create_light(const char* name) {
    Light* light = (Light*)malloc(sizeof(Light));
    strncpy(light->name, name, MAX_DEV_NAME);
    light->is_on = 0; // 初始关闭
    light->turn_on = light_turn_on;
    light->turn_off = light_turn_off;
    return light;
}

// 接收者2:音响(支持音量调节)
typedef struct Audio {
    char name[MAX_DEV_NAME];
    int volume; // 音量:0-100
    void (*vol_up)(struct Audio* self, int step);
    void (*vol_down)(struct Audio* self, int step);
} Audio;

void audio_vol_up(Audio* self, int step) {
    self->volume = (self->volume + step) > 100 ? 100 : (self->volume + step);
    printf("[%s] 音量调大%d → 当前音量:%d\n", self->name, step, self->volume);
}

void audio_vol_down(Audio* self, int step) {
    self->volume = (self->volume - step) < 0 ? 0 : (self->volume - step);
    printf("[%s] 音量调小%d → 当前音量:%d\n", self->name, step, self->volume);
}

Audio* create_audio(const char* name) {
    Audio* audio = (Audio*)malloc(sizeof(Audio));
    strncpy(audio->name, name, MAX_DEV_NAME);
    audio->volume = 50; // 初始音量50
    audio->vol_up = audio_vol_up;
    audio->vol_down = audio_vol_down;
    return audio;
}

// -------------------------- 2. 抽象命令(Command):命令统一接口 --------------------------
// 命令类型枚举(用于区分命令,辅助撤销)
typedef enum {
    CMD_LIGHT_ON,
    CMD_LIGHT_OFF,
    CMD_AUDIO_VOL_UP,
    CMD_AUDIO_VOL_DOWN
} CmdType;

// 抽象命令结构体(包含执行、撤销接口,以及命令元信息)
typedef struct Command {
    CmdType type;          // 命令类型(用于撤销时识别)
    void* receiver;        // 命令接收者(Light/Audio)
    void (*execute)(struct Command* self); // 执行命令
    void (*undo)(struct Command* self);    // 撤销命令
    void* extra;           // 命令额外参数(如音量调节步长)
    void (*destroy)(struct Command* self); // 销毁命令
} Command;

// -------------------------- 3. 具体命令(ConcreteCommand):绑定接收者与操作 --------------------------
// 具体命令:开灯(额外参数无)
typedef struct LightOnCmd {
    Command base;
} LightOnCmd;

void light_on_execute(Command* self) {
    Light* light = (Light*)self->receiver;
    light->turn_on(light);
}

void light_on_undo(Command* self) {
    // 撤销开灯 → 关灯
    Light* light = (Light*)self->receiver;
    light->turn_off(light);
    printf("[撤销命令] 开灯 → 恢复为关灯\n");
}

void light_on_destroy(Command* self) {
    free(self);
}

Command* create_light_on_cmd(Light* light) {
    LightOnCmd* cmd = (LightOnCmd*)malloc(sizeof(LightOnCmd));
    cmd->base.type = CMD_LIGHT_ON;
    cmd->base.receiver = light;
    cmd->base.execute = light_on_execute;
    cmd->base.undo = light_on_undo;
    cmd->base.extra = NULL;
    cmd->base.destroy = light_on_destroy;
    return (Command*)cmd;
}

// 具体命令:关灯(额外参数无)
typedef struct LightOffCmd {
    Command base;
} LightOffCmd;

void light_off_execute(Command* self) {
    Light* light = (Light*)self->receiver;
    light->turn_off(light);
}

void light_off_undo(Command* self) {
    // 撤销关灯 → 开灯
    Light* light = (Light*)self->receiver;
    light->turn_on(light);
    printf("[撤销命令] 关灯 → 恢复为开灯\n");
}

void light_off_destroy(Command* self) {
    free(self);
}

Command* create_light_off_cmd(Light* light) {
    LightOffCmd* cmd = (LightOffCmd*)malloc(sizeof(LightOffCmd));
    cmd->base.type = CMD_LIGHT_OFF;
    cmd->base.receiver = light;
    cmd->base.execute = light_off_execute;
    cmd->base.undo = light_off_undo;
    cmd->base.extra = NULL;
    cmd->base.destroy = light_off_destroy;
    return (Command*)cmd;
}

// 具体命令:音响音量调大(额外参数:调节步长)
typedef struct AudioVolUpCmd {
    Command base;
    int step; // 调节步长(额外参数)
    int prev_volume; // 执行前的音量(用于撤销)
} AudioVolUpCmd;

void audio_vol_up_execute(Command* self) {
    AudioVolUpCmd* cmd = (AudioVolUpCmd*)self;
    Audio* audio = (Audio*)self->receiver;
    cmd->prev_volume = audio->volume; // 记录执行前状态(用于撤销)
    audio->vol_up(audio, cmd->step);
}

void audio_vol_up_undo(Command* self) {
    AudioVolUpCmd* cmd = (AudioVolUpCmd*)self;
    Audio* audio = (Audio*)self->receiver;
    audio->volume = cmd->prev_volume; // 恢复执行前的音量
    printf("[撤销命令] 音量调大 → 恢复为:%d\n", cmd->prev_volume);
}

void audio_vol_up_destroy(Command* self) {
    free(self);
}

Command* create_audio_vol_up_cmd(Audio* audio, int step) {
    AudioVolUpCmd* cmd = (AudioVolUpCmd*)malloc(sizeof(AudioVolUpCmd));
    cmd->base.type = CMD_AUDIO_VOL_UP;
    cmd->base.receiver = audio;
    cmd->base.execute = audio_vol_up_execute;
    cmd->base.undo = audio_vol_up_undo;
    cmd->base.extra = NULL;
    cmd->base.destroy = audio_vol_up_destroy;
    cmd->step = step;
    cmd->prev_volume = 0;
    return (Command*)cmd;
}

// 具体命令:音响音量调小(额外参数:调节步长)
typedef struct AudioVolDownCmd {
    Command base;
    int step; // 调节步长
    int prev_volume; // 执行前的音量(用于撤销)
} AudioVolDownCmd;

void audio_vol_down_execute(Command* self) {
    AudioVolDownCmd* cmd = (AudioVolDownCmd*)self;
    Audio* audio = (Audio*)self->receiver;
    cmd->prev_volume = audio->volume; // 记录执行前状态
    audio->vol_down(audio, cmd->step);
}

void audio_vol_down_undo(Command* self) {
    AudioVolDownCmd* cmd = (AudioVolDownCmd*)self;
    Audio* audio = (Audio*)self->receiver;
    audio->volume = cmd->prev_volume; // 恢复音量
    printf("[撤销命令] 音量调小 → 恢复为:%d\n", cmd->prev_volume);
}

void audio_vol_down_destroy(Command* self) {
    free(self);
}

Command* create_audio_vol_down_cmd(Audio* audio, int step) {
    AudioVolDownCmd* cmd = (AudioVolDownCmd*)malloc(sizeof(AudioVolDownCmd));
    cmd->base.type = CMD_AUDIO_VOL_DOWN;
    cmd->base.receiver = audio;
    cmd->base.execute = audio_vol_down_execute;
    cmd->base.undo = audio_vol_down_undo;
    cmd->base.extra = NULL;
    cmd->base.destroy = audio_vol_down_destroy;
    cmd->step = step;
    cmd->prev_volume = 0;
    return (Command*)cmd;
}

// -------------------------- 4. 调用者(Invoker):遥控器(管理命令队列和撤销) --------------------------
typedef struct RemoteControl {
    Command* cmd_queue[MAX_CMD_QUEUE]; // 命令队列(待执行/已执行)
    Command* undo_stack[MAX_CMD_QUEUE];// 撤销栈(存储已执行的命令,用于撤销)
    int queue_size;                    // 命令队列长度
    int undo_top;                      // 撤销栈栈顶索引

    // 接口:添加命令到队列
    void (*add_cmd)(struct RemoteControl* self, Command* cmd);
    // 接口:执行队列中所有命令
    void (*execute_all)(struct RemoteControl* self);
    // 接口:撤销最后一个执行的命令
    void (*undo_last)(struct RemoteControl* self);
    // 接口:销毁遥控器(释放命令队列和撤销栈)
    void (*destroy)(struct RemoteControl* self);
} RemoteControl;

// 调用者:添加命令到队列
void remote_add_cmd(RemoteControl* self, Command* cmd) {
    if (self->queue_size >= MAX_CMD_QUEUE) {
        printf("遥控器命令队列已满,无法添加新命令!\n");
        return;
    }
    self->cmd_queue[self->queue_size++] = cmd;
    printf("遥控器添加命令:%d\n", cmd->type);
}

// 调用者:执行所有命令(并压入撤销栈)
void remote_execute_all(RemoteControl* self) {
    if (self->queue_size == 0) {
        printf("遥控器无待执行命令!\n");
        return;
    }
    printf("\n=== 遥控器执行所有命令 ===\n");
    for (int i = 0; i < self->queue_size; i++) {
        Command* cmd = self->cmd_queue[i];
        cmd->execute(cmd);
        // 执行后压入撤销栈
        if (self->undo_top < MAX_CMD_QUEUE) {
            self->undo_stack[self->undo_top++] = cmd;
        }
    }
    // 执行完成后清空命令队列(可根据需求保留)
    self->queue_size = 0;
}

// 调用者:撤销最后一个命令
void remote_undo_last(RemoteControl* self) {
    if (self->undo_top == 0) {
        printf("\n无命令可撤销!\n");
        return;
    }
    printf("\n=== 遥控器撤销最后一个命令 ===\n");
    Command* cmd = self->undo_stack[--self->undo_top];
    cmd->undo(cmd);
    // 撤销后可将命令放回队列(或丢弃,根据需求)
}

// 调用者:销毁(释放所有命令)
void remote_destroy(RemoteControl* self) {
    if (self != NULL) {
        // 释放命令队列
        for (int i = 0; i < self->queue_size; i++) {
            self->cmd_queue[i]->destroy(self->cmd_queue[i]);
        }
        // 释放撤销栈
        for (int i = 0; i < self->undo_top; i++) {
            self->undo_stack[i]->destroy(self->undo_stack[i]);
        }
        free(self);
        printf("\n遥控器已销毁\n");
    }
}

// 创建遥控器(调用者)
RemoteControl* create_remote_control() {
    RemoteControl* remote = (RemoteControl*)malloc(sizeof(RemoteControl));
    remote->queue_size = 0;
    remote->undo_top = 0;
    remote->add_cmd = remote_add_cmd;
    remote->execute_all = remote_execute_all;
    remote->undo_last = remote_undo_last;
    remote->destroy = remote_destroy;
    return remote;
}

// -------------------------- 测试代码(客户端) --------------------------
int main() {
    // 1. 创建接收者(家电)
    Light* living_room_light = create_light("客厅灯");
    Audio* living_room_audio = create_audio("客厅音响");

    // 2. 创建调用者(遥控器)
    RemoteControl* remote = create_remote_control();

    // 3. 创建具体命令(客户端绑定命令与接收者)
    Command* cmd1 = create_light_on_cmd(living_room_light);       // 开灯
    Command* cmd2 = create_audio_vol_up_cmd(living_room_audio, 20); // 音量+20
    Command* cmd3 = create_audio_vol_up_cmd(living_room_audio, 10); // 音量+10

    // 4. 客户端添加命令到遥控器(发送者无需知道接收者)
    remote->add_cmd(remote, cmd1);
    remote->add_cmd(remote, cmd2);
    remote->add_cmd(remote, cmd3);

    // 5. 执行所有命令
    remote->execute_all(remote);

    // 6. 撤销最后一个命令(音量+10 → 恢复)
    remote->undo_last(remote);

    // 7. 再添加一个命令(关灯)并执行
    Command* cmd4 = create_light_off_cmd(living_room_light);
    remote->add_cmd(remote, cmd4);
    remote->execute_all(remote);

    // 8. 撤销(关灯 → 开灯)
    remote->undo_last(remote);

    // 9. 资源释放
    remote->destroy(remote);
    free(living_room_light);
    free(living_room_audio);

    return 0;
}

实现关键要点

1.角色模拟清晰:
接收者(Light/Audio):封装具体操作(开关、调音量),不依赖命令;
抽象命令(Command):用函数指针定义 execute/undo 统一接口,屏蔽具体命令差异;
具体命令:绑定接收者和操作,记录撤销所需的状态(如音量调节前的数值);
调用者(RemoteControl):管理命令队列和撤销栈,负责触发命令执行 / 撤销。
2.解耦核心:客户端(main)仅需创建命令并添加到调用者,发送者(遥控器)无需知道接收者(家电)如何执行,接收者也无需知道命令来源。
3.撤销实现:具体命令需记录执行前的状态(如 prev_volume),undo 方法恢复该状态,确保撤销逻辑可逆。
4.内存管理:调用者销毁时需释放命令队列和撤销栈中的所有命令,避免内存泄漏;接收者需手动释放(或在命令中管理,根据设计)。
5.扩展性:新增家电(如空调)或命令(如调温)时,仅需新增接收者结构体和具体命令结构体,无需修改调用者(遥控器)代码,符合开闭原则。
6.队列支持:调用者通过数组实现命令队列,支持批量执行多个命令(如一键启动所有家电)。

C++语言实现

通过 “抽象基类 + 纯虚函数” 定义命令接口,利用继承和多态实现具体命令,STL 容器管理命令队列,智能指针自动管理内存,代码更简洁、类型更安全。

场景示例

同 C 语言:家电控制系统(接收者 Light/Audio、抽象命令 Command、具体命令、调用者 RemoteControl),支持命令队列、执行、撤销。

#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <memory> // 智能指针

// -------------------------- 1. 接收者(Receiver):家电类 --------------------------
// 灯(接收者)
class Light {
public:
    explicit Light(std::string name) : name_(std::move(name)), is_on_(false) {}

    void TurnOn() {
        is_on_ = true;
        std::cout << "[" << name_ << "] 开灯成功(当前状态:开启)" << std::endl;
    }

    void TurnOff() {
        is_on_ = false;
        std::cout << "[" << name_ << "] 关灯成功(当前状态:关闭)" << std::endl;
    }

private:
    std::string name_;
    bool is_on_;
};

// 音响(接收者)
class Audio {
public:
    explicit Audio(std::string name) : name_(std::move(name)), volume_(50) {}

    void VolUp(int step) {
        volume_ = std::min(volume_ + step, 100);
        std::cout << "[" << name_ << "] 音量调大" << step << " → 当前音量:" << volume_ << std::endl;
    }

    void VolDown(int step) {
        volume_ = std::max(volume_ - step, 0);
        std::cout << "[" << name_ << "] 音量调小" << step << " → 当前音量:" << volume_ << std::endl;
    }

    // 供命令获取当前音量(用于撤销)
    int GetVolume() const { return volume_; }
    // 供命令恢复音量(用于撤销)
    void SetVolume(int volume) { volume_ = volume; }

private:
    std::string name_;
    int volume_;
};

// -------------------------- 2. 抽象命令(Command):抽象基类 --------------------------
class Command {
public:
    virtual ~Command() = default; // 虚析构:确保子类析构被调用
    virtual void Execute() = 0;   // 纯虚函数:执行命令
    virtual void Undo() = 0;      // 纯虚函数:撤销命令
};

// -------------------------- 3. 具体命令(ConcreteCommand) --------------------------
// 开灯命令
class LightOnCommand : public Command {
public:
    explicit LightOnCommand(std::shared_ptr<Light> light) : light_(std::move(light)) {}

    void Execute() override {
        light_->TurnOn();
    }

    void Undo() override {
        light_->TurnOff();
        std::cout << "[撤销命令] 开灯 → 恢复为关灯" << std::endl;
    }

private:
    std::shared_ptr<Light> light_; // 持有接收者(智能指针自动管理内存)
};

// 关灯命令
class LightOffCommand : public Command {
public:
    explicit LightOffCommand(std::shared_ptr<Light> light) : light_(std::move(light)) {}

    void Execute() override {
        light_->TurnOff();
    }

    void Undo() override {
        light_->TurnOn();
        std::cout << "[撤销命令] 关灯 → 恢复为开灯" << std::endl;
    }

private:
    std::shared_ptr<Light> light_;
};

// 音响音量调大命令
class AudioVolUpCommand : public Command {
public:
    AudioVolUpCommand(std::shared_ptr<Audio> audio, int step) 
        : audio_(std::move(audio)), step_(step), prev_volume_(0) {}

    void Execute() override {
        prev_volume_ = audio_->GetVolume(); // 记录执行前状态
        audio_->VolUp(step_);
    }

    void Undo() override {
        audio_->SetVolume(prev_volume_); // 恢复状态
        std::cout << "[撤销命令] 音量调大 → 恢复为:" << prev_volume_ << std::endl;
    }

private:
    std::shared_ptr<Audio> audio_;
    int step_;          // 调节步长
    int prev_volume_;   // 执行前音量(用于撤销)
};

// 音响音量调小命令
class AudioVolDownCommand : public Command {
public:
    AudioVolDownCommand(std::shared_ptr<Audio> audio, int step) 
        : audio_(std::move(audio)), step_(step), prev_volume_(0) {}

    void Execute() override {
        prev_volume_ = audio_->GetVolume();
        audio_->VolDown(step_);
    }

    void Undo() override {
        audio_->SetVolume(prev_volume_);
        std::cout << "[撤销命令] 音量调小 → 恢复为:" << prev_volume_ << std::endl;
    }

private:
    std::shared_ptr<Audio> audio_;
    int step_;
    int prev_volume_;
};

// -------------------------- 4. 调用者(Invoker):遥控器 --------------------------
class RemoteControl {
public:
    ~RemoteControl() = default;

    // 添加命令到队列
    void AddCommand(std::shared_ptr<Command> cmd) {
        cmd_queue_.push_back(cmd);
        std::cout << "遥控器添加命令" << std::endl;
    }

    // 执行队列中所有命令(并压入撤销栈)
    void ExecuteAll() {
        if (cmd_queue_.empty()) {
            std::cout << "遥控器无待执行命令!" << std::endl;
            return;
        }
        std::cout << "\n=== 遥控器执行所有命令 ===" << std::endl;
        for (const auto& cmd : cmd_queue_) {
            cmd->Execute();
            undo_stack_.push(cmd); // 执行后入栈,用于撤销
        }
        cmd_queue_.clear(); // 执行完成清空队列
    }

    // 撤销最后一个命令
    void UndoLast() {
        if (undo_stack_.empty()) {
            std::cout << "\n无命令可撤销!" << std::endl;
            return;
        }
        std::cout << "\n=== 遥控器撤销最后一个命令 ===" << std::endl;
        auto cmd = undo_stack_.top();
        undo_stack_.pop();
        cmd->Undo();
    }

private:
    std::vector<std::shared_ptr<Command>> cmd_queue_; // 命令队列
    std::stack<std::shared_ptr<Command>> undo_stack_; // 撤销栈(存储已执行命令)
};

// -------------------------- 测试代码(客户端) --------------------------
int main() {
    // 1. 创建接收者(智能指针自动管理内存)
    auto living_room_light = std::make_shared<Light>("客厅灯");
    auto living_room_audio = std::make_shared<Audio>("客厅音响");

    // 2. 创建调用者(遥控器)
    RemoteControl remote;

    // 3. 创建具体命令(绑定接收者)
    auto cmd1 = std::make_shared<LightOnCommand>(living_room_light);
    auto cmd2 = std::make_shared<AudioVolUpCommand>(living_room_audio, 20);
    auto cmd3 = std::make_shared<AudioVolUpCommand>(living_room_audio, 10);

    // 4. 添加命令到遥控器
    remote.AddCommand(cmd1);
    remote.AddCommand(cmd2);
    remote.AddCommand(cmd3);

    // 5. 执行所有命令
    remote.ExecuteAll();

    // 6. 撤销最后一个命令
    remote.UndoLast();

    // 7. 添加新命令并执行
    auto cmd4 = std::make_shared<LightOffCommand>(living_room_light);
    remote.AddCommand(cmd4);
    remote.ExecuteAll();

    // 8. 撤销
    remote.UndoLast();

    return 0; // 智能指针自动销毁所有对象,无需手动释放
}

实现关键要点

1.抽象基类定义接口:Command 基类用纯虚函数 Execute/Undo 定义统一命令接口,具体命令类继承并实现,确保多态调用。
2.智能指针管理内存:接收者和命令均用 std::shared_ptr 管理,自动释放内存,避免内存泄漏;虚析构函数确保子类析构被正确调用。
3.解耦彻底:调用者(RemoteControl)仅依赖 Command 抽象基类,不依赖具体命令和接收者;客户端仅需绑定命令与接收者,发送者无需知道执行细节。
4.STL 容器简化管理:用 std::vector 实现命令队列,std::stack 实现撤销栈,无需手动维护数组索引,代码更简洁。
5.撤销逻辑清晰:具体命令类记录执行前的状态(如 prev_volume_),Undo 方法恢复该状态,可逆性强。
6.扩展性强:新增命令(如空调调温)时,仅需新增 AirConditioner 接收者类和 AirConditionerSetTempCommand 命令类,无需修改调用者代码,完全符合开闭原则。
7.类型安全:C++ 的编译期类型检查和多态机制,避免 C 语言中函数指针绑定错误或类型转换风险,代码更可靠。

命令模式核心总结(C vs C++)

在这里插入图片描述

设计原则

开闭原则:新增命令无需修改现有代码;
单一职责原则:命令负责封装请求,接收者负责执行操作,调用者负责管理命令;
依赖倒置原则:调用者依赖抽象命令,不依赖具体命令和接收者。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值