设计模式(C++)-行为型模式-命令模式

设计模式(C++)-行为型模式-命令模式

一、命令模式概述

命令模式(command pattern):是一种行为型模式,它将请求封装为对象,从而允许你参数化客户端对象,将请求排队,记录请求日志,以及支持可撤销的操作。
核心思想 :"将请求封装为对象",使请求的发送者和接收者解耦。发送者只需要知道如何发送命令,不需要知道命令如何执行或由谁执行。

在C/C++中实现命令模式,你可以遵循以下步骤:

定义命令接口:一个接口,定义了一个执行操作的方法,通常叫做 execute。

实现具体命令:创建实现了命令接口的具体类,这些类包含了对特定操作的调用。

定义客户端:客户端是一个创建和配置命令对象的对象,然后将其传递给请求者。

请求者:请求者是一个知道如何去执行命令的对象,它通常持有一个命令对象的引用或指针。

调用对象:这是实际执行操作的对象,它可能由具体命令内部使用。

可选 - 引入撤销机制:如果需要,可以为命令添加撤销操作

二、命令模式UML类图

命令模式场景

假如现在有一个游戏服务器,该游戏服务器一共可以处理四种不同的请求:处理增加金币、处理增加钻石、处理玩家装备、玩家升级请求。我们需要把这些请求封装成对象,从而加入请求队列一次进行处理。

三、代码实现

cpp 复制代码
//command.h
#pragma once
/*
命令模式(Command Pattern)
是一种行为设计模式,它将一个请求封装为一个对象,从而允许用户使用不同的请求、队列或日志请求来参数化其他对象。
命令模式也支持可撤销的操作。它通常用于将调用操作的对象与知道如何实现该操作的对象解耦。
在C/C++中实现命令模式,你可以遵循以下步骤:
定义命令接口:一个接口,定义了一个执行操作的方法,通常叫做 execute。
实现具体命令:创建实现了命令接口的具体类,这些类包含了对特定操作的调用。
定义客户端:客户端是一个创建和配置命令对象的对象,然后将其传递给请求者。
请求者:请求者是一个知道如何去执行命令的对象,它通常持有一个命令对象的引用或指针。
调用对象:这是实际执行操作的对象,它可能由具体命令内部使用。
可选 - 引入撤销机制:如果需要,可以为命令添加撤销操作
例子:
假如现在有一个游戏服务器,该游戏服务器一共可以处理四种不同的请求:处理增加金币、处理增加钻石、处理玩家装备、玩家升级请求。
我们需要把这些请求封装成对象,从而加入请求队列一次进行处理。
*/
#include <iostream>
#include <queue>
#include <memory>
using namespace std;
class Request{
public:
	//处理增加金币
	void AddMoney()
	{
		cout << "给玩家增加金币" << endl;
	}
	//处理增加钻石
	void AddDiamond()
	{
		cout << "给玩家增加钻石" << endl;
	}
	//处理玩家装备
	void AddEquipment()
	{
		cout << "给玩家穿装备" << endl;
	}
	//玩家升级
	void AddLevel()
	{
		cout << "给玩家升级" << endl;
	}
};
//定义命令接口类
class AbstractCommand {
public:
	virtual void excute()=0;
};
//下面是把每一个请求封装为一个请求对象
//处理增加金币请求
class AddMoneyCommand :public AbstractCommand {
public:
	AddMoneyCommand(std::shared_ptr<Request> request) :m_request(std::move(request)) {};
	virtual void excute();
private:
	std::shared_ptr<Request> m_request;
};

//处理增加组钻石请求
class AddDiamondCommand :public AbstractCommand {
public:
	AddDiamondCommand(std::shared_ptr<Request> request) :m_request(std::move(request)) {};
	virtual void excute();
private:
	std::shared_ptr<Request> m_request;
};

//处理增加玩家装备请求
class AddEquitmentCommand :public AbstractCommand {
public:
	AddEquitmentCommand(std::shared_ptr<Request> request) :m_request(std::move(request)) {};
	virtual void excute();
private:
	std::shared_ptr<Request> m_request;
};

//处理玩家升级请求
class AddLevelCommand :public AbstractCommand {
public:
	AddLevelCommand(std::shared_ptr<Request> request) :m_request(std::move(request)) {};
	virtual void excute();
private:
	std::shared_ptr<Request> m_request;
};

//服务器程序(命令调用类)
class Server {
public:
	//将请求对象放入处理队列
	void addRequest(std::shared_ptr<AbstractCommand>command);
	//启动处理程序
	void startExcute();
private:
	queue<std::shared_ptr<AbstractCommand> > m_commands;
};

void testCommand();

//command.cc
#include "command.h"
#include <thread>
void AddMoneyCommand::excute() {
	m_request->AddMoney();
}
void AddDiamondCommand::excute() {
	m_request->AddDiamond();
}
void AddEquitmentCommand::excute() {
	m_request->AddEquipment();
}
void AddLevelCommand::excute() {
	m_request->AddLevel();
}
//将请求对象放入处理队列
void Server::addRequest(std::shared_ptr<AbstractCommand>command) {
	m_commands.push(command);
}
//启动处理程序
void Server::startExcute() {
	while (!m_commands.empty())
	{
		std::shared_ptr<AbstractCommand> command = std::move(m_commands.front());
		std::this_thread::sleep_for(std::chrono::seconds(2));
		command->excute();
		m_commands.pop();
	}
}
void testCommand() {
	cout << "=================command start===============" << endl;
	std::shared_ptr<Request> request = std::make_shared<Request>();
	//客户端增加金币的请求
	std::shared_ptr<AddMoneyCommand> addmoney = std::make_shared<AddMoneyCommand>(std::move(request));
	//客户端增加钻石的请求
	std::shared_ptr<AddDiamondCommand>addiamond = std::make_shared<AddDiamondCommand>(std::move(request));
	//客户端增加装备的请求
	std::shared_ptr<AddEquitmentCommand> addquitment = std::make_shared<AddEquitmentCommand>(std::move(request));
	//客户端升级的请求
	std::shared_ptr<AddLevelCommand> addlevel = std::make_shared<AddLevelCommand>(std::move(request));

	//将客户端的请求加入到请求队列中
	std::shared_ptr<Server> server = std::make_shared<Server>();
	server->addRequest(std::move(addmoney));
	server->addRequest(std::move(addiamond));
	server->addRequest(std::move(addquitment));
	server->addRequest(std::move(addlevel));

	//服务器开始处理请求
	server->startExcute();

	cout << "=================command end===============" << endl;
}

四、优缺点总结

优点:

  • 解耦调用者和接收者:调用者不需要知道接收者的具体细节
  • 支持撤销/重做:可以轻松实现撤销和重做功能
  • 支持事务:可以将多个命令组合成一个事务
  • 支持命令队列:可以实现命令的排队、延迟执行
  • 易于扩展:添加命令不需要修改现有代码
  • 支持宏命令:可以组合多个命令

缺点:

  • 类的数量增加:每个命令都需要一个具体的命令类
  • 增加系统复杂性:对于简单操作,可能过于复杂
  • 可能产生大量小对象:每个命令都是一个对象
相关推荐
6Hzlia1 小时前
【Hot 100 刷题计划】 LeetCode 189. 轮转数组 | C++ 三次反转经典魔法 (O(1) 空间)
c++·算法·leetcode
darkhorsefly1 小时前
《智能体设计模式》
设计模式
淀粉肠kk1 小时前
【C++11】智能指针详解
开发语言·c++
不想写代码的星星1 小时前
COW(Copy-on-Write):开抄开抄,哎嘿,我装的
开发语言·c++
Sylvia-girl1 小时前
C++内存如何管理?
java·jvm·c++
无敌秋2 小时前
C++ 单例模式
c++·单例模式
Brilliantwxx2 小时前
【C++】认识标准库STL(2)
开发语言·c++
故事还在继续吗2 小时前
STL 容器算法手册
开发语言·c++·算法
啊我不会诶2 小时前
2023西安邀请赛vp补题
c++·算法