命令模式:讲一个请求封装成一个对象,可以让不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作,别名为事务模式或者动作模式;这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理。
命令模式将请求发送者与接受者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求
命令模式的优点是降低系统的耦合度,增加或删除命令非常方便
缺点是可能产生大量具体命令类。因为计对每一个具体操作都需要设计一个具体命令类,这将增加系统的复杂性
定义三个角色:1、received 真正的命令执行对象 2、Command 3、invoker 使用命令对象的入口
使用场景:认为是命令的地方都可以使用命令模式,比如: 1、GUI 中每一个按钮都是一条命令。 2、模拟 CMD。
模式的结构:
抽象命令类(Command):声明执行命令的接口,拥有执行命令的抽象方法 execute()。
具体命令类(Concrete Command):是抽象命令类的具体实现类,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。
实现者/接收者(Receiver):执行命令功能的相关操作,是具体命令对象业务的真正实现者。
调用者/请求者(Invoker):是请求的发送者,它通常拥有很多的命令对象,并通过访问命令对象来执行相关请求,它不直接访问接收者。
//命令处理类
class HandleClientProtocol {
public:
//处理增加金币
void AddMoney() {
cout << "给玩家增加金币!" << endl;
}
//处理增加钻石
void AddDiamond() {
cout << "给玩家增加钻石!" << endl;
}
};
//抽象命令类
class AbstractCommand {
public:
virtual void handle() = 0; //处理客户端请求的接口
};
//具体命令类-处理增加金币请求
class AddMoneyCommand :public AbstractCommand {
public:
AddMoneyCommand(HandleClientProtocol* protocol) {
this->pProtocol = protocol;
}
virtual void handle() {
this->pProtocol->AddMoney();
}
public:
HandleClientProtocol* pProtocol;
};
//具体命令类-处理增加钻石的请求
class AddDiamondCommand :public AbstractCommand {
public:
AddDiamondCommand(HandleClientProtocol* protocol) {
this->pProtocol = protocol;
}
virtual void handle() {
this->pProtocol->AddDiamond();
}
public:
HandleClientProtocol* pProtocol;
};
//接收者-服务器程序
class Serser {
public:
void addRequest(AbstractCommand* command) {
mCommands.push(command);
}
void startHandle() {
while (!mCommands.empty()) {
Sleep(1000);
AbstractCommand* command = mCommands.front();
command->handle();
mCommands.pop();
}
}
public:
queue<AbstractCommand*> mCommands;
};
//Invoker-调用者
void test() {
HandleClientProtocol* protocol = new HandleClientProtocol;
//客户端增加金币的请求
AbstractCommand* addmoney = new AddMoneyCommand(protocol);
//客户端增加钻石的请求
AbstractCommand* adddiamond = new AddDiamondCommand(protocol);
Serser* server = new Serser;
//将客户端请求加入到处理的队列中
server->addRequest(addmoney);
server->addRequest(adddiamond);
//服务器开始处理请求
server->startHandle();
}