行为型模式:②命令模式(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++)

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

被折叠的 条评论
为什么被折叠?



