设计模式(C)-行为型模式-命令模式一、命令模式概述命令模式(command pattern)是一种行为型模式它将请求封装为对象从而允许你参数化客户端对象将请求排队记录请求日志以及支持可撤销的操作。核心思想:“将请求封装为对象”使请求的发送者和接收者解耦。发送者只需要知道如何发送命令不需要知道命令如何执行或由谁执行。在C/C中实现命令模式你可以遵循以下步骤定义命令接口一个接口定义了一个执行操作的方法通常叫做 execute。实现具体命令创建实现了命令接口的具体类这些类包含了对特定操作的调用。定义客户端客户端是一个创建和配置命令对象的对象然后将其传递给请求者。请求者请求者是一个知道如何去执行命令的对象它通常持有一个命令对象的引用或指针。调用对象这是实际执行操作的对象它可能由具体命令内部使用。可选 - 引入撤销机制如果需要可以为命令添加撤销操作二、命令模式UML类图命令模式场景假如现在有一个游戏服务器该游戏服务器一共可以处理四种不同的请求处理增加金币、处理增加钻石、处理玩家装备、玩家升级请求。我们需要把这些请求封装成对象从而加入请求队列一次进行处理。三、代码实现//command.h#pragmaonce/* 命令模式Command Pattern 是一种行为设计模式它将一个请求封装为一个对象从而允许用户使用不同的请求、队列或日志请求来参数化其他对象。 命令模式也支持可撤销的操作。它通常用于将调用操作的对象与知道如何实现该操作的对象解耦。 在C/C中实现命令模式你可以遵循以下步骤 定义命令接口一个接口定义了一个执行操作的方法通常叫做 execute。 实现具体命令创建实现了命令接口的具体类这些类包含了对特定操作的调用。 定义客户端客户端是一个创建和配置命令对象的对象然后将其传递给请求者。 请求者请求者是一个知道如何去执行命令的对象它通常持有一个命令对象的引用或指针。 调用对象这是实际执行操作的对象它可能由具体命令内部使用。 可选 - 引入撤销机制如果需要可以为命令添加撤销操作 例子: 假如现在有一个游戏服务器该游戏服务器一共可以处理四种不同的请求处理增加金币、处理增加钻石、处理玩家装备、玩家升级请求。 我们需要把这些请求封装成对象从而加入请求队列一次进行处理。 */#includeiostream#includequeue#includememoryusingnamespacestd;classRequest{public://处理增加金币voidAddMoney(){cout给玩家增加金币endl;}//处理增加钻石voidAddDiamond(){cout给玩家增加钻石endl;}//处理玩家装备voidAddEquipment(){cout给玩家穿装备endl;}//玩家升级voidAddLevel(){cout给玩家升级endl;}};//定义命令接口类classAbstractCommand{public:virtualvoidexcute()0;};//下面是把每一个请求封装为一个请求对象//处理增加金币请求classAddMoneyCommand:publicAbstractCommand{public:AddMoneyCommand(std::shared_ptrRequestrequest):m_request(std::move(request)){};virtualvoidexcute();private:std::shared_ptrRequestm_request;};//处理增加组钻石请求classAddDiamondCommand:publicAbstractCommand{public:AddDiamondCommand(std::shared_ptrRequestrequest):m_request(std::move(request)){};virtualvoidexcute();private:std::shared_ptrRequestm_request;};//处理增加玩家装备请求classAddEquitmentCommand:publicAbstractCommand{public:AddEquitmentCommand(std::shared_ptrRequestrequest):m_request(std::move(request)){};virtualvoidexcute();private:std::shared_ptrRequestm_request;};//处理玩家升级请求classAddLevelCommand:publicAbstractCommand{public:AddLevelCommand(std::shared_ptrRequestrequest):m_request(std::move(request)){};virtualvoidexcute();private:std::shared_ptrRequestm_request;};//服务器程序(命令调用类)classServer{public://将请求对象放入处理队列voidaddRequest(std::shared_ptrAbstractCommandcommand);//启动处理程序voidstartExcute();private:queuestd::shared_ptrAbstractCommandm_commands;};voidtestCommand();//command.cc#includecommand.h#includethreadvoidAddMoneyCommand::excute(){m_request-AddMoney();}voidAddDiamondCommand::excute(){m_request-AddDiamond();}voidAddEquitmentCommand::excute(){m_request-AddEquipment();}voidAddLevelCommand::excute(){m_request-AddLevel();}//将请求对象放入处理队列voidServer::addRequest(std::shared_ptrAbstractCommandcommand){m_commands.push(command);}//启动处理程序voidServer::startExcute(){while(!m_commands.empty()){std::shared_ptrAbstractCommandcommandstd::move(m_commands.front());std::this_thread::sleep_for(std::chrono::seconds(2));command-excute();m_commands.pop();}}voidtestCommand(){coutcommand startendl;std::shared_ptrRequestrequeststd::make_sharedRequest();//客户端增加金币的请求std::shared_ptrAddMoneyCommandaddmoneystd::make_sharedAddMoneyCommand(std::move(request));//客户端增加钻石的请求std::shared_ptrAddDiamondCommandaddiamondstd::make_sharedAddDiamondCommand(std::move(request));//客户端增加装备的请求std::shared_ptrAddEquitmentCommandaddquitmentstd::make_sharedAddEquitmentCommand(std::move(request));//客户端升级的请求std::shared_ptrAddLevelCommandaddlevelstd::make_sharedAddLevelCommand(std::move(request));//将客户端的请求加入到请求队列中std::shared_ptrServerserverstd::make_sharedServer();server-addRequest(std::move(addmoney));server-addRequest(std::move(addiamond));server-addRequest(std::move(addquitment));server-addRequest(std::move(addlevel));//服务器开始处理请求server-startExcute();coutcommand endendl;}四、优缺点总结优点解耦调用者和接收者调用者不需要知道接收者的具体细节支持撤销/重做可以轻松实现撤销和重做功能支持事务可以将多个命令组合成一个事务支持命令队列可以实现命令的排队、延迟执行易于扩展添加命令不需要修改现有代码支持宏命令可以组合多个命令缺点类的数量增加每个命令都需要一个具体的命令类增加系统复杂性对于简单操作可能过于复杂可能产生大量小对象每个命令都是一个对象