前言
今天复习了命令模式,感觉挺有意思的,这里跟大家分享下!
1. 命令模式理解
命令模式,就是将命令发出人与命令执行人分开,让它们不直接联系,而是通过第三者记录这些命令,然后再由这个第三者把这些命令告诉命令执行人去执行,这中间可以在以前命令的基础上新增或者删除命令,实现了松耦合。
《大话设计模式》中举了个很恰当的例子:买烤串的人和烤串的人。路边摊上买烤串的人都是直接告诉烤串者自己要什么,人多的话,容易出错。有了命令模式后,就相当于烤串者有了铺面,有了服务员,有了菜单,买烤串的人直接和服务员沟通,服务员将客户要求记录在菜单上,然后服务员将菜单通过厨房传递给烤串者,这样烤串者就可以按照这一张张菜单来烤串了,再也不用担心出错了,既方便计算账单,也方便客户退单等。
命令模式比较正规的定义与类图(引用《大话设计模式》)如下所示:
上述类图中,Client就等同于买烤串的人,Invoker就相当于服务员,Command就相当于菜单,上面记录了一条条客户点的串,Receiver就相当于做烤串的人,是不是很清晰明了!
2. 命令模式C++实现
这里以在店铺吃烤串为例实现命令模式,类图(引用《大话设计模式》)如下所示:
C++代码实现如下:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <memory>
#include <list>
#include <chrono>
// 获取系统当前时间
std::string getCurrentSystemTime()
{
auto tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
struct tm* ptm = localtime(&tt);
char date[60] = { 0 };
sprintf(date, "%d-%02d-%02d-%02d.%02d.%02d",
(int)ptm->tm_year + 1900, (int)ptm->tm_mon + 1, (int)ptm->tm_mday,
(int)ptm->tm_hour, (int)ptm->tm_min, (int)ptm->tm_sec);
return std::string(date);
}
//**************************Command Pattern*********************
//烤肉串者
class Barbecuer
{
public:
void BakeMutton()
{
std::cout << "烤羊肉串!" << std::endl;
}
void BakeChickenWing()
{
std::cout << "烤鸡翅!" << std::endl;
}
};
//抽象命令类
class Command
{
protected:
std::shared_ptr<Barbecuer> smartBarbecuer;
std::string strDescription;
public:
Command(std::shared_ptr<Barbecuer> pBarbecuer, const std::string& strDesc): smartBarbecuer(pBarbecuer), strDescription(strDesc) {}
virtual void ExecuteCommand() = 0;
std::string GetDescription() const
{
return strDescription;
}
};
//烤羊肉串命令
class BakeMuttonCommand : public Command
{
public:
BakeMuttonCommand(std::shared_ptr<Barbecuer> receiver, const std::string& strDesc = "烤羊肉串"): Command(receiver, strDesc){}
void ExecuteCommand()
{
smartBarbecuer->BakeMutton();
}
};
//烤鸡翅串命令
class BakeChickenWingCommand : public Command
{
public:
BakeChickenWingCommand(std::shared_ptr<Barbecuer> receiver, const std::string& strDesc = "烤鸡翅串") : Command(receiver, strDesc) {}
void ExecuteCommand()
{
smartBarbecuer->BakeChickenWing();
}
};
//服务员类
class Waiter
{
private:
std::list<std::shared_ptr<Command>> orders;
public:
void SetOrder(std::shared_ptr<Command> command)
{
if (command->GetDescription() == "烤鸡翅串")
{
std::cout << "服务员:鸡翅没有了,请点儿别的吧!" << std::endl;
}
else
{
orders.push_back(command);
std::cout << "增加订单:" << command->GetDescription().c_str() << ", 时间:" << getCurrentSystemTime().c_str() << std::endl;
}
}
void CancelOrder(std::shared_ptr<Command> command)
{
orders.remove(command);
std::cout << "取消订单:" << command->GetDescription().c_str() << ", 时间: " << getCurrentSystemTime().c_str() << std::endl;
}
void Notify()
{
std::cout << "订单来了,厨房可以开始烤串了!" << std::endl;
for (std::shared_ptr<Command> command : orders)
{
command->ExecuteCommand();
}
}
};
//****************************Test******************************
int main()
{
//开店前准备
std::shared_ptr<Barbecuer> boy = std::make_shared<Barbecuer>();
std::shared_ptr<Command> bakeMuttonC1 = std::make_shared<BakeMuttonCommand>(boy);
std::shared_ptr<Command> bakeMuttonC2 = std::make_shared<BakeMuttonCommand>(boy);
std::shared_ptr<Command> bakeChickenWingC1 = std::make_shared<BakeChickenWingCommand>(boy);
std::shared_ptr<Waiter> waiter = std::make_shared<Waiter>();
//开始营业,顾客点菜
waiter->SetOrder(bakeMuttonC1);
waiter->SetOrder(bakeMuttonC2);
waiter->SetOrder(bakeChickenWingC1);
//点菜完毕,通知厨房
waiter->Notify();
//顾客取消订单
waiter->CancelOrder(bakeMuttonC1);
//点菜完毕,通知厨房
waiter->Notify();
system("pause");
return 0;
}
总结
命令模式实现了请求者与实现者的分离,实现了松耦合,提高了扩展性。
个人感觉,命令模式是组合关系和事物抽象能力的应用产出的结果。事物抽象能力很重要,如果抽象能力运用的好,设计模式的运用就不是难事了!
参考
《大话设计模式》