1. 命令模式基础与C++实现
命令模式是GoF 23种设计模式中最具实用性的行为型模式之一,它将请求封装为独立对象,使不同请求的参数化、队列化和日志化成为可能。在C++中实现经典命令模式通常包含以下核心组件:
- Command:抽象命令接口,声明执行操作的execute()方法
- ConcreteCommand:具体命令实现,绑定接收者与动作
- Invoker:触发命令执行的调用者
- Receiver:知道如何执行请求的实际操作对象
典型实现如下:
cpp复制// 接收者类
class Receiver {
public:
void Action() {
std::cout << "Receiver执行实际操作" << std::endl;
}
};
// 抽象命令接口
class Command {
public:
virtual ~Command() = default;
virtual void Execute() = 0;
};
// 具体命令
class ConcreteCommand : public Command {
public:
ConcreteCommand(Receiver* receiver) : receiver_(receiver) {}
void Execute() override {
receiver_->Action();
}
private:
Receiver* receiver_;
};
// 调用者
class Invoker {
public:
void SetCommand(Command* command) {
command_ = command;
}
void ExecuteCommand() {
if (command_) {
command_->Execute();
}
}
private:
Command* command_ = nullptr;
};
这种基础实现虽然清晰,但在实际C++项目中往往会遇到几个典型问题:
- 命令对象生命周期管理复杂(原始指针易导致内存泄漏)
- 不支持参数化命令构造
- 缺乏撤销/重做等扩展功能
- 多线程环境下命令调度存在竞态条件
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 现代C++命令模式变体实现
2.1 智能指针管理命令生命周期
使用std::unique_ptr可以优雅解决命令对象的所有权问题:
cpp复制class Invoker {
public:
void SetCommand(std::unique_ptr<Command> command) {
command_ = std::move(command);
}
void ExecuteCommand() {
if (command_) {
command_->Execute();
}
}
private:
std::unique_ptr<Command> command_;
};
// 使用示例
auto receiver = std::make_unique<Receiver>();
auto command = std::make_unique<ConcreteCommand>(receiver.get());
Invoker invoker;
invoker.SetCommand(std::move(command));
invoker.ExecuteCommand();
注意:当需要共享命令对象时,应使用std::shared_ptr,但要注意避免循环引用
2.2 模板化命令接口
通过模板技术可以实现类型安全的命令参数传递:
cpp复制template <typename Receiver, typename... Args>
class GenericCommand : public Command {
public:
using ActionType = void (Receiver::*)(Args...);
GenericCommand(Receiver* receiver, ActionType action, Args... args)
: receiver_(receiver), action_(action), args_(std::forward<Args>(args)...) {}
void Execute() override {
std::apply([this](auto&&... args) {
(receiver_->*action_)(std::forward<decltype(args)>(args)...);
}, args_);
}
private:
Receiver* receiver_;
ActionType action_;
std::tuple<Args...> args_;
};
// 使用示例
struct Document {
void InsertText(const std::string& text, int position) {
std::cout << "在位置" << position << "插入文本:" << text << std::endl;
}
};
Document doc;
auto cmd = std::make_unique<GenericCommand<Document, std::string, int>>(
&doc, &Document::InsertText, "Hello", 5);
cmd->Execute(); // 输出:在位置5插入文本:Hello
2.3 支持撤销/重做的命令模式
扩展命令接口增加撤销功能:
cpp复制class UndoableCommand : public Command {
public:
virtual void Undo() = 0;
virtual bool CanUndo() const { return true; }
};
class InsertCommand : public UndoableCommand {
public:
InsertCommand(Document* doc, const std::string& text, int pos)
: doc_(doc), text_(text), pos_(pos) {}
void Execute() override {
doc_->InsertText(text_, pos_);
executed_ = true;
}
void Undo() override {
if (executed_) {
doc_->DeleteText(pos_, text_.length());
executed_ = false;
}
}
private:
Document* doc_;
std::string text_;
int pos_;
bool executed_ = false;
};
// 命令历史管理器
class CommandHistory {
public:
void Push(std::unique_ptr<UndoableCommand> cmd) {
undoStack_.push(std::move(cmd));
// 清空重做栈
while (!redoStack_.empty()) redoStack_.pop();
}
void Undo() {
if (!undoStack_.empty()) {
auto cmd = std::move(undoStack_.top());
undoStack_.pop();
cmd->Undo();
redoStack_.push(std::move(cmd));
}
}
void Redo() {
if (!redoStack_.empty()) {
auto cmd = std::move(redoStack_.top());
redoStack_.pop();
cmd->Execute();
undoStack_.push(std::move(cmd));
}
}
private:
std::stack<std::unique_ptr<UndoableCommand>> undoStack_;
std::stack<std::unique_ptr<UndoableCommand>> redoStack_;
};
3. 命令模式在C++项目中的高级应用
3.1 异步命令执行
结合C++11的异步特性实现非阻塞命令执行:
cpp复制class AsyncCommand : public Command {
public:
explicit AsyncCommand(std::function<void()> action)
: action_(std::move(action)) {}
void Execute() override {
future_ = std::async(std::launch::async, action_);
}
void Wait() {
if (future_.valid()) {
future_.wait();
}
}
private:
std::function<void()> action_;
std::future<void> future_;
};
// 使用示例
auto asyncCmd = std::make_unique<AsyncCommand>([]() {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "异步命令执行完成" << std::endl;
});
invoker.SetCommand(std::move(asyncCmd));
invoker.ExecuteCommand(); // 立即返回
3.2 组合命令(宏命令)
实现命令的批处理执行:
cpp复制class MacroCommand : public Command {
public:
void AddCommand(std::unique_ptr<Command> cmd) {
commands_.push_back(std::move(cmd));
}
void Execute() override {
for (auto& cmd : commands_) {
cmd->Execute();
}
}
private:
std::vector<std::unique_ptr<Command>> commands_;
};
// 使用示例
auto macro = std::make_unique<MacroCommand>();
macro->AddCommand(std::make_unique<ConcreteCommand>(receiver1));
macro->AddCommand(std::make_unique<ConcreteCommand>(receiver2));
invoker.SetCommand(std::move(macro));
invoker.ExecuteCommand(); // 依次执行所有子命令
3.3 命令模式与事件总线结合
构建基于事件的命令系统:
cpp复制class EventBus {
public:
template <typename Event>
void Publish(Event&& event) {
for (auto& subscriber : subscribers_) {
if (auto* handler = dynamic_cast<EventHandler<Event>*>(subscriber.get())) {
handler->Handle(std::forward<Event>(event));
}
}
}
template <typename Event>
void Subscribe(std::unique_ptr<EventHandler<Event>> handler) {
subscribers_.push_back(std::move(handler));
}
private:
std::vector<std::unique_ptr<IEventHandler>> subscribers_;
};
template <typename Event>
class EventHandler {
public:
virtual void Handle(Event&& event) = 0;
virtual ~EventHandler() = default;
};
class CommandEvent {
public:
explicit CommandEvent(std::unique_ptr<Command> cmd) : command_(std::move(cmd)) {}
Command* GetCommand() const { return command_.get(); }
private:
std::unique_ptr<Command> command_;
};
class CommandEventHandler : public EventHandler<CommandEvent> {
public:
void Handle(CommandEvent&& event) override {
if (auto* cmd = event.GetCommand()) {
cmd->Execute();
}
}
};
4. 性能优化与线程安全
4.1 命令对象池
对于频繁创建销毁的命令对象,使用对象池优化:
cpp复制template <typename CommandType>
class CommandPool {
public:
template <typename... Args>
std::unique_ptr<CommandType> Acquire(Args&&... args) {
if (pool_.empty()) {
return std::make_unique<CommandType>(std::forward<Args>(args)...);
}
auto cmd = std::move(pool_.top());
pool_.pop();
cmd->Reset(std::forward<Args>(args)...);
return cmd;
}
void Release(std::unique_ptr<CommandType> cmd) {
pool_.push(std::move(cmd));
}
private:
std::stack<std::unique_ptr<CommandType>> pool_;
};
// 可重置命令接口
class ResettableCommand : public Command {
public:
virtual void Reset() = 0;
};
4.2 线程安全命令队列
多线程环境下的安全命令执行:
cpp复制class ThreadSafeCommandQueue {
public:
void Push(std::unique_ptr<Command> cmd) {
std::lock_guard<std::mutex> lock(mutex_);
queue_.push(std::move(cmd));
cv_.notify_one();
}
std::unique_ptr<Command> Pop() {
std::unique_lock<std::mutex> lock(mutex_);
cv_.wait(lock, [this] { return !queue_.empty(); });
auto cmd = std::move(queue_.front());
queue_.pop();
return cmd;
}
private:
std::queue<std::unique_ptr<Command>> queue_;
std::mutex mutex_;
std::condition_variable cv_;
};
// 命令消费者线程
void CommandConsumer(ThreadSafeCommandQueue& queue) {
while (true) {
auto cmd = queue.Pop();
cmd->Execute();
}
}
4.3 命令执行性能分析
通过装饰器模式添加性能监控:
cpp复制class ProfilingCommandDecorator : public Command {
public:
explicit ProfilingCommandDecorator(std::unique_ptr<Command> cmd)
: decorated_(std::move(cmd)) {}
void Execute() override {
auto start = std::chrono::high_resolution_clock::now();
decorated_->Execute();
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "命令执行耗时: " << duration.count() << "μs" << std::endl;
}
private:
std::unique_ptr<Command> decorated_;
};
5. 实际项目中的设计考量
5.1 命令序列化与持久化
实现命令的序列化接口:
cpp复制class SerializableCommand : public Command {
public:
virtual std::string Serialize() const = 0;
virtual void Deserialize(const std::string& data) = 0;
};
class NetworkCommand : public SerializableCommand {
public:
void Execute() override {
// 通过网络发送序列化后的命令
std::string data = Serialize();
// ...网络传输逻辑
}
std::string Serialize() const override {
// 实现序列化逻辑
return "";
}
void Deserialize(const std::string& data) override {
// 实现反序列化逻辑
}
};
5.2 命令优先级与调度策略
扩展命令接口支持优先级:
cpp复制class PrioritizedCommand : public Command {
public:
explicit PrioritizedCommand(int priority) : priority_(priority) {}
int GetPriority() const { return priority_; }
bool operator<(const PrioritizedCommand& other) const {
return priority_ < other.priority_;
}
private:
int priority_;
};
class CommandScheduler {
public:
void Schedule(std::unique_ptr<PrioritizedCommand> cmd) {
queue_.push(std::move(cmd));
}
void ExecuteAll() {
while (!queue_.empty()) {
auto cmd = std::move(queue_.top());
queue_.pop();
cmd->Execute();
}
}
private:
std::priority_queue<std::unique_ptr<PrioritizedCommand>> queue_;
};
5.3 命令模式与C++20协程
利用C++20协程实现异步命令流:
cpp复制struct CommandAwaiter {
Command* cmd;
bool await_ready() const { return false; }
void await_suspend(std::coroutine_handle<> h) {
cmd->SetCompletionCallback([h]() { h.resume(); });
cmd->Execute();
}
void await_resume() {}
};
CommandAwaiter operator co_await(Command& cmd) {
return CommandAwaiter{&cmd};
}
Task<> ProcessCommands() {
Command cmd1, cmd2;
co_await cmd1; // 等待命令1完成
co_await cmd2; // 等待命令2完成
}
在实际C++项目中应用命令模式时,有几个关键决策点需要考虑:
-
命令粒度:过细会导致命令爆炸,过粗会降低灵活性。通常根据业务操作的原子性来确定。
-
内存管理策略:根据命令使用频率选择栈分配、unique_ptr共享或对象池复用。
-
线程模型:单线程顺序执行、多线程并行执行或基于事件循环的异步执行。
-
撤销/重做深度:无限撤销会消耗大量内存,需要设计合理的快照机制或压缩算法。
-
命令持久化格式:JSON、Protocol Buffers等序列化方案的选择取决于跨平台需求。
