设计模式–命令模式
思路
有一个请求类,里面有不同的请求,需要把一个个命令都用对象封装起来,并且这些命令都继承一个命令接口。然后在使用的时候把对象都放入到一个队列里面进行处理。
优点
1.低耦合性:命令模式将请求的发送者和接收者完全解耦。发送者(如Server类)只需要知道如何发送命令(调用execute方法),而不需要了解接收者(如HandleClinetProtocal类)的具体实现细节。
2.扩展和维护性:当接收者的内部实现发生变化,比如修改了某个方法的具体算法或者添加了新的功能方法,只要命令对象(如AddMoneyCommand等)的接口不变,发送者的代码就不需要修改。同样,如果要添加新的接收者,只要创建对应的命令类并实现命令接口,就可以轻松地集成到系统中。
3.支持命令的排队、记录和撤销 / 重做功能:把命令放在一个请求队列里面,可以保持命名的顺序性,并且可以保留操作命令历史,用户实现撤销功能。
设计
有一个请求命令类,里面记录不同的命令。再有一个抽象命令类,里面有一个虚函数execute(),后续就可以继承这个抽象命令类写一些具体命令类,里面有一个请求命令类的指针,然后在虚函数里面使用具体命令类想要完成请求命令类里面的哪个命令。最后有一个请求队列类,用于接收和处理请求对象。
下面例子是服务器处理用户请求的一个案例,用户有升级、获取金币、穿装备三个请求。
#include <iostream>
#include <queue>
#include <memory>
using namespace std;
// 请求接收者(执行者)
class HandleClinetProtocal {
public:
void AddMoney() {
cout << "给玩家增加金币" << endl;
}
void AddEquipment() {
cout << "给玩家穿装备" << endl;
}
void AddLevel() {
cout << "给玩家升级" << endl;
}
};
// 抽象命令
class AbstractCommand {
public:
virtual void execute() = 0;
virtual ~AbstractCommand() = default;
};
// 增加金币命令
class AddMoneyCommand : public AbstractCommand {
public:
AddMoneyCommand(shared_ptr<HandleClinetProtocal> protocal) : pProtocol(protocal) {}
void execute() override {
pProtocol->AddMoney();
}
private:
shared_ptr<HandleClinetProtocal> pProtocol;
};
// 增加装备命令
class AddEquipmentCommand : public AbstractCommand {
public:
AddEquipmentCommand(shared_ptr<HandleClinetProtocal> protocal) : pProtocol(protocal) {}
void execute() override {
pProtocol->AddEquipment();
}
private:
shared_ptr<HandleClinetProtocal> pProtocol;
};
// 增加等级命令
class AddLevelCommand : public AbstractCommand {
public:
AddLevelCommand(shared_ptr<HandleClinetProtocal> protocal) : pProtocol(protocal) {}
void execute() override {
pProtocol->AddLevel();
}
private:
shared_ptr<HandleClinetProtocal> pProtocol;
};
// 服务器(命令调用者)
class Server {
public:
// 将请求对象放入处理队列
void addRequest(shared_ptr<AbstractCommand> command) {
mCommands.push(command);
}
// 启动处理程序
void startHandle() {
while (!mCommands.empty()) {
auto command = mCommands.front();
command->execute();
mCommands.pop();
}
}
private:
queue<shared_ptr<AbstractCommand>> mCommands;
};
int main() {
auto protocal = make_shared<HandleClinetProtocal>();
auto addmoney = make_shared<AddMoneyCommand>(protocal);
auto addequipment = make_shared<AddEquipmentCommand>(protocal);
auto addlevel = make_shared<AddLevelCommand>(protocal);
Server server;
server.addRequest(addmoney);
server.addRequest(addequipment);
server.addRequest(addlevel);
server.startHandle();
return 0;
}
给玩家增加金币
给玩家穿装备
给玩家升级
有一个请求命令类HandleClinetProtocal指针,然后具体命令类里面也有一个HandleClinetProtocal指针接收传入指针,会根据需求使用里面的哪个命令。
再把需要执行的命令对象放入到请求队列,由于都是重写虚函数execute,所以可以直接循环取出并执行命令对象。