【C++设计模式】命令模式

本文深入探讨了软件设计中的命令模式,详细介绍了其角色、定义及意义。通过实例展示如何使用命令模式解耦请求者与接收者,实现命令的队列化、撤销/恢复等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#ifndef __COMMAND_H__
#define __COMMAND_H__

#include <iostream>
#include <list>

//【说明】
// 命令模式是为了解决命令的请求者和命令的实现者之间的耦合关系。
// Command对象在执行命令时,并不一定自己切身做这件事,而是将请求转发给另一个真正做这件事情的对象(Receiver对象),由Receiver对象最终完成请求操作。

//【定义】
// 命令模式(Command):把一个请求或者操作封装到一个对象中。从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持撤销和恢复功能。

//【角色】
// 命令(Command)角色:声明了一个给所有具体命令类的抽象接口。
// 具体命令(ConcreteCommand)角色:定义一个接收者和行为之间的弱耦合;实现execute()方法,负责调用接收者的相应操作。
// 接收者(Receiver)角色:负责具体实施和执行一个请求。任何一个类都可以成为接收者,实施和执行请求的方法叫做行动方法。
// 请求者(Invoker)角色:负责调用命令对象执行请求。
// 客户端(Client)角色:创建一个具体命令(ConcreteCommand)对象并确定其接收者。

//【意义】
// 松散的耦合,命令模式使得命令的发起对象和执行对象完全解耦,可以更方便的对命令进行扩展。
// 可以更容易的实现对多个命令的统一控制,这种控制包括但不限于:队列、撤销/恢复、记录日志等等。

//【示例】


//Command类,用来声明执行操作的接口
class iCommand
{
public:
	iCommand(){ }

	virtual ~iCommand(){ }

public:
	virtual void execute() = 0;
};

//Receiver类,真正执行请求相关操作的接口,任何类都可能作为一个接收者。
class iReceiver
{
public:
	iReceiver(){ }

	virtual ~iReceiver(){ }

public:
	virtual void execute() = 0;
};

//播放音乐命令
class PlayCommand : public iCommand
{
public:
	PlayCommand(iReceiver * recv) : m_recv(recv){ }

	virtual void execute();
private:
	iReceiver *m_recv;
};

//烹饪命令
class CookCommand : public iCommand
{
public:
	CookCommand(iReceiver * recv) : m_recv(recv){ }

	virtual void execute();
private:
	iReceiver *m_recv;
};

//播放器
class MediaPlayer : public iReceiver
{
public:
	virtual void execute();
};

//厨师
class Chef : public iReceiver
{
public:
	virtual void execute();
};

//如果客户端需要多种命令能够按照某个队列依次执行,我们需要把命令的执行者从客户端中分离出来。
//引入一个对象叫调度者,Invoker类,来控制命令的队列化和可撤销操作等,对命令进行管理。
class Invoker
{
public:
	void AddCommand(iCommand * cmd);

	int  ExecuteCommand();

	void CancelCommand(iCommand * com);

	void RollbackCommand(iCommand * com);

private:	
	std::list<iCommand*> m_cmdlist;
	std::list<iCommand*> m_historycmdlist;
};

void TestCommand();

#endif

#include "Command.h"

void PlayCommand::execute()
{
	m_recv->execute();
}

void CookCommand::execute()
{
	m_recv->execute();
}

void MediaPlayer::execute()
{
	printf("start play music.\n");
}

void Chef::execute()
{
	printf("start cook.\n");
}

void Invoker::AddCommand(iCommand* cmd)
{
	m_cmdlist.push_back(cmd);
}

int Invoker::ExecuteCommand()
{
	if (!m_cmdlist.empty())
	{
		iCommand * cmd = NULL;

		cmd = m_cmdlist.front();

		cmd->execute();

		m_cmdlist.pop_front();

		m_historycmdlist.push_back(cmd);
	}

	return -1;
}

void Invoker::CancelCommand(iCommand *com)
{
	//遍历命令队列,找到命令并删除
}

void Invoker::RollbackCommand(iCommand *com)
{
	//找到历史命令,并执行状态还原
}

void TestCommand()
{
	iReceiver * chef   = new Chef();

	iCommand * cookcmd = new CookCommand(chef);

	iReceiver * player = new MediaPlayer();

	iCommand * playcmd = new PlayCommand(player);

	Invoker * inv = new Invoker();

	inv->AddCommand(playcmd);

	inv->AddCommand(cookcmd);

	inv->ExecuteCommand();

	inv->ExecuteCommand();

	delete inv;
	delete chef;
	delete cookcmd;
	delete player;
	delete playcmd;
}


 

### C++命令模式的设计与实现 #### 什么是命令模式命令模式是一种行为型设计模式,它通过将请求封装为对象来解耦发送者和接收者的依赖关系。这种模式允许参数化请求、支持队列请求以及提供撤销/重做的功能[^1]。 #### 命令模式的核心组件 - **抽象命令类 (Command)**:定义执行操作的接口。 - **具体命令类 (ConcreteCommand)**:实现了抽象命令类中的方法,并绑定具体的接收者及其动作。 - **接收者 (Receiver)**:实际执行命令的对象。 - **调用者 (Invoker)**:负责触发命令的执行。 - **客户端 (Client)**:创建具体命令对象并将其设置给调用者。 以下是基于上述概念的一个完整的命令模式实现示例: ```cpp #include <iostream> #include <memory> // 接收者类 class Receiver { public: void action() const { std::cout << "Receiver performs an action." << std::endl; } }; // 抽象命令类 #pragma once class Command { public: virtual ~Command() {} virtual void execute() = 0; virtual void undo() = 0; }; // 具体命令类 class ConcreteCommand : public Command { private: Receiver& receiver; public: explicit ConcreteCommand(Receiver& r) : receiver(r) {} void execute() override { receiver.action(); } void undo() override { std::cout << "Undoing the command..." << std::endl; } }; // 调用者类 class Invoker { private: std::unique_ptr<Command> command; public: void set_command(std::unique_ptr<Command> cmd) { command = std::move(cmd); } void invoke() { if (command) { command->execute(); } else { std::cout << "No command to execute!" << std::endl; } } void undo() { if (command) { command->undo(); } else { std::cout << "No command to undo!" << std::endl; } } }; int main() { // 创建接收者 Receiver receiver; // 创建具体命令并将接收者传递进去 auto concreteCommand = std::make_unique<ConcreteCommand>(receiver); // 创建调用者并关联命令 Invoker invoker; invoker.set_command(std::move(concreteCommand)); // 执行命令 invoker.invoke(); // 撤销命令 invoker.undo(); return 0; } ``` #### 关键点解析 1. **抽象命令类的作用** 定义了一个通用接口 `execute` 和 `undo` 方法,所有的具体命令都需继承该接口并实现其方法。 2. **具体命令类的功能** 将接收者的行为与其自身的逻辑结合起来,在 `execute` 方法中调用了接收者的特定方法[^3]。 3. **调用者的职责** 提供了统一的操作入口,即 `invoke()` 和 `undo()` 方法,使高层模块无需关心底层细节即可完成任务。 4. **优势分析** - 支持扩展性强,新增加的具体命令只需遵循现有接口标准即可无缝接入系统。 - 解决了直接调用带来的紧耦合问题,增强了系统的灵活性和可维护性[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值