1. 什么是命令模式?
命令模式(Command):将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
2. 命令模式的适用场景?
2.1 优缺点
优点:
第一、能较容易地设计一个命令队列
第二、在需要的情况下,可以较容易地将命令计入日志
第三、允许接收请求的一方决定是否否决请求
第四、可以容易地实现对请求的撤销和重做
第五、由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易。
最关键优点:命令模式将请求一个操作的对象与指导怎么执行一个操作的对象分割开。
2.2 何时使用?
Q:是否配到类似的情况是否就一定要实现命令模式?
A:未必,当我们不清楚是否需要这个功能时,不用实现命令模式。原因如下:
敏捷开发有讲到:不要对代码添加基于猜测、而实际不需要的功能。
如果不清楚一个系统是否需要命令模式,一般就不要着急去实现它;、事实上,在需要的时候通过重构实现这个模式并不困难,只有在正在需要如撤销/恢复操作等功能时,把原来的代码重构为命令模式才有意义。
3. 怎样使用命令模式?
3.1 方法
原始需求:单个类的职责太多,不好维护。
1、分解单个类职责(命令执行者+命令接收传达者)
2、使用抽象命令类连接命令执行者与命令接收传达者。
达到类职责细化的目的。
3.2 UML类图
4. 实例
需求:个人烧烤摊,用户多了,请求多了,算账容易乱。
方法:职责细化,招人(服务员)
1、需要把烤串人的职责单一化,烤串人只管命令告诉他拷什么
抽象一个命令类出来,用来隔离服务员类与烤串人。
2、有多种烤串术语(命令)是烤串人与服务员共同遵守的知识。
命令这里就可以做文章,基类命令服务与外部类交接命令的传达与接收,执行(抽象接口),
子类命令可以派生出N个,分别实现执行接口,即可做好一个好的命令系统。
3、新增的服务员类,有两个责任:1 记录客户的命令需求(点单);2将命令通知给烤串人。
这样,通过实现抽象的命令类与服务员类,就可以实现烤串人与顾客之间的松耦合了。
4.1 结果(结论先行)
#include "ICommand.h"
#include "BakeMuttonCmd.h"
#include "BakeChickenWingCmd.h"
#include "Waiter.h"
void test()
{
CBarbecuer* boy = new CBarbecuer();
ICommand* pBakeMuttonCmd = new CBakeMuttonCmd(boy);
ICommand* pBakeChickenWingCmd = new CBakeChickenWingCmd(boy);
CWaiter* girl = new CWaiter();
//开门营业
girl->order(pBakeMuttonCmd);
girl->notify();
girl->order(pBakeMuttonCmd);
girl->notify();
girl->order(pBakeChickenWingCmd);
girl->notify();
delete boy;
delete pBakeMuttonCmd;
delete pBakeChickenWingCmd;
delete girl;
boy = nullptr;
pBakeMuttonCmd = nullptr;
pBakeChickenWingCmd = nullptr;
girl = nullptr;
}
int main()
{
test();
system("pause");
return 0;
}
4.2 具体实现
4.2.1 ICommand.h
#pragma once
#include "Barbecuer.h"
class ICommand
{
public:
ICommand(CBarbecuer* pBarbecuer);
~ICommand();
//执行命令(做菜)
virtual void exec() = 0;
protected:
//命令接受者(烤串人)
CBarbecuer* m_pReceiver{ nullptr };
};
ICommand::ICommand(CBarbecuer* pBarbecuer)
{
this->m_pReceiver = pBarbecuer;
}
ICommand::~ICommand()
{
m_pReceiver = nullptr;
}
4.2.2 Waiter.h
#pragma once
#include "ICommand.h"
class CWaiter
{
public:
//点单
void order(ICommand* pCmd);
//通知后厨
void notify();
private:
ICommand* m_pCmd{ nullptr };
};
void CWaiter::order(ICommand* pCmd)
{
m_pCmd = pCmd;
}
void CWaiter::notify()
{
m_pCmd->exec();
}
4.4.3 BakeMuttonCmd.h
#pragma once
#include "ICommand.h"
class CBakeMuttonCmd :
public ICommand
{
public:
CBakeMuttonCmd(CBarbecuer* pBarbecuer = nullptr);
virtual void exec() override;
};
CBakeMuttonCmd::CBakeMuttonCmd(CBarbecuer* pBarbecuer /*= nullptr*/)
:ICommand(pBarbecuer)
{
}
void CBakeMuttonCmd::exec()
{
m_pReceiver->BakeMutton();//真正的妙处在这里啊,执行时,命令让烤串人去烤串
}
4.4.4 BakeChickenWingCmd.h
#pragma once
#include "ICommand.h"
class CBakeChickenWingCmd :
public ICommand
{
public:
CBakeChickenWingCmd(CBarbecuer* pBarbecuer = nullptr);
virtual void exec() override;
};
CBakeChickenWingCmd::CBakeChickenWingCmd(CBarbecuer* pBarbecuer /*= nullptr*/)
:ICommand(pBarbecuer)
{
}
void CBakeChickenWingCmd::exec()
{
m_pReceiver->BakeChickenWing();
}
4.4.5 Barbecuer.h
#pragma once
#include <iostream>
using namespace std;
class CBarbecuer
{
public:
void BakeMutton();//烤羊肉
void BakeChickenWing();//拷鸡翅
};
void CBarbecuer::BakeMutton()
{
cout << "烤羊肉串" << endl;
}
void CBarbecuer::BakeChickenWing()
{
cout << "烤鸡翅" << endl;
}
此为《大话设计模式》学习心得系列 P237~~
命令模式相关链接:
《大话设计模式》C++实现:23 命令模式(二)进阶版
《大话设计模式》C++实现:23 命令模式(二)进阶版2
《大话设计模式》C++实现:23 命令模式(三)抽象总结