命令模式:將“請求”封裝成對象,以便使用不同的請求、隊列或者日誌來參數化其他對象。命令模式也支持可撤銷的操作。
命令(Command):爲所有命令聲明瞭一個接口。調用命令對象的 execute()方法,就可以讓接收者進行相關的操作。這個接口也具備一個 undo() 方法。
命令模式把請求一個操作的對象與知道怎麼執行一個操作的對象分隔開,從而使新的命令類可以很容易被加入到系統當中
組成部分
1、調用者(Invoker):持有一個命令對象,並在某個時間點調用命令對象的execute()方法。
2、命令對象(Command):持有一個接收者,和一個execute()方法,在execute中執行接收者的動作。
3、接收者(Receiver):動作的執行者。
優點:
1、能夠比較容易的設計一個命令隊列
2、需要的情況下,可以很容易的將命令記入日誌
3、允許接受者決定是否要否決請求
4、可以很容易的實現對請求的撤銷和重做
5、新添加的命令類,不影響其它的類,因此新添加的具體命令類很容易
缺點:使用命令模式可能會導致某些系統有過多的具體命令類。
應用場景:
1、真正需要撤銷\恢復等操作的時候,用命令模式
2、需要對命令記錄日誌
3、請求和執行分離開
#include <iostream>
#include <string>
#include <list>
#include<windows.h>
using namespace std;
//typedef std::list<Command*> ListCommand; // 命令列表
#define SAFE_DELETE(p) if (p) { delete p; p = NULL; }
// 烤肉師傅類
class Barbecuer
{
public:
void BakeMutton()
{
cout << "Bake mutton" << endl;
}
void BakeChickenWing()
{
cout << "Bake ChickenWing" << endl;
}
void BakeChichenLeg()
{
cout << "Bake ChichenLeg" << endl;
}
};
// 抽象命令類,提供執行接口
class Command
{
public:
Command()
{
}
Command(Barbecuer *receiver) :p_receiver(receiver)
{
}
virtual void ExecuteCommand() = 0; //執行命令
protected:
Barbecuer *p_receiver;
};
//具體命令類:烤羊肉串命令
class BakeMuttonCommand :public Command
{
public:
BakeMuttonCommand(Barbecuer *receiver)
{
p_receiver = receiver;
}
void ExecuteCommand()
{
p_receiver->BakeMutton();
}
};
//具體命令類:烤雞翅串命令 open
class BakeChickenWingCommand :public Command
{
public:
BakeChickenWingCommand(Barbecuer *receiver)
{
p_receiver = receiver;
}
void ExecuteCommand()
{
p_receiver->BakeChickenWing();
}
};
// 具體命令類
class BakeChickenLegCommand :public Command
{
public:
BakeChickenLegCommand(Barbecuer *receiver)
{
p_receiver = receiver;
}
void ExecuteCommand()
{
p_receiver->BakeChichenLeg();
}
};
// 服務員類
class Waiter
{
public:
void SetOrder(Command *command);
void CancleOrder(Command *command);
void Notify();
private:
std::list<Command*> p_commandList; // 命令對象列表
};
void Waiter::SetOrder(Command *command)
{
p_commandList.push_back(command);
cout << "增加烤肉命令" << endl;
}
void Waiter::CancleOrder(Command *command)
{
p_commandList.remove(command);
cout << "移除烤肉命令" << endl;
}
void Waiter::Notify()
{
std::list<Command*>::iterator iterCommand;
for (iterCommand = p_commandList.begin(); iterCommand != p_commandList.end(); ++iterCommand)
(*iterCommand)->ExecuteCommand();
}
int main(int argc, char *argv[])
{
//生成烤肉師傅、服務員、訂單對象
Barbecuer *p_cook = new Barbecuer(); //
Command *p_mutton = new BakeMuttonCommand(p_cook);
Command *p_chickenwing = new BakeChickenWingCommand(p_cook);
Command *p_chickenLeg = new BakeChickenLegCommand(p_cook);
Waiter *p_waiter = new Waiter();
// 顧客點菜
p_waiter->SetOrder(p_mutton);
p_waiter->SetOrder(p_chickenwing);
p_waiter->SetOrder(p_chickenLeg);
p_waiter->CancleOrder(p_chickenwing);
//服務員通知烤肉師傅具體訂單
p_waiter->Notify();
SAFE_DELETE(p_cook);
SAFE_DELETE(p_mutton);
SAFE_DELETE(p_chickenwing);
SAFE_DELETE(p_waiter);
system("pause");
return 0;
}
使用場景:認爲是命令的地方都可以使用命令模式,比如: 1、GUI 中每一個按鈕都是一條命令。 2、模擬 CMD。
另外回調函數和命令模式還是有區別的,首先命令作爲類對象,它的方法更多一些;其次,命令對象可以做撤回操作