命令模式

来源:互联网 发布:淘宝手机贷款 编辑:程序博客网 时间:2024/06/05 13:57
1.概述
将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求队列或者记录请求日志,可以提供命令的撤销和恢复功能。

2.UML图

角色描述:
Receiver:接受者角色,就是干活的厨师,命令传递到这里就应该被执行。
Command:命令角色,对命令封装,所有命令声明在此
Invoker:调用者角色,接受到命令并且执行命令 

3.代码实现
#include <iostream>#include <list>using namespace std;#define SAFE_RELEASE(_p){ if((_p)){ delete (_p); (_p) = NULL;} }class Cook{public:virtual void BakeMutton() = 0;//烤羊肉virtual void BakeChickenWing() = 0;//烤鸡翅protected:stringm_name;};class ConcreteCook : public Cook{public:ConcreteCook(string name) { m_name = name; }virtual void BakeMutton() { cout<<"Cook: "<<m_name.c_str()<<" bake mutton"<<endl; }virtual void BakeChickenWing() { cout<<"Cook: "<<m_name.c_str()<<" bake chicken wing"<<endl; }};/*抽象命令类:是执行具体操作的接口*/class Command{public:Command(Cook* cook) : m_recever(cook) {}virtual void ExecuteCommand() = 0;//执行命令protected:Cook*m_recever;};class BakeMuttonCmd : public Command{public:BakeMuttonCmd(Cook* cook) : Command(cook) {}virtual void ExecuteCommand() { m_recever->BakeMutton(); }};class BakeChickenWingCmd : public Command{public:BakeChickenWingCmd(Cook* cook) : Command(cook) {}virtual void ExecuteCommand() { m_recever->BakeChickenWing(); }};/*服务员类*/class Waiter{public:void SetOrder(Command* c) { m_cmdlist.push_back(c); }void Notify(){for (list<Command*>::iterator iter = m_cmdlist.begin(); iter != m_cmdlist.end(); iter++){(*iter)->ExecuteCommand();}}private:list<Command*>m_cmdlist;};int main(int argc, char* argv[]){//生成厨师、服务员、订单对象Cook* cook1 = new ConcreteCook("zhangsan");Cook* cook2 = new ConcreteCook("lisi");//指定某个厨师Command* command1 = new BakeMuttonCmd(cook1);Command* command2 = new BakeChickenWingCmd(cook2);Waiter* pWaiter = new Waiter();//将订单对象推送到命令队列pWaiter->SetOrder(command1);pWaiter->SetOrder(command2);pWaiter->Notify();SAFE_RELEASE(cook1);SAFE_RELEASE(cook2);SAFE_RELEASE(command1);SAFE_RELEASE(command2);SAFE_RELEASE(pWaiter);return 0;}
模式分析
对命令进行封装,将发出命令与执行命令的责任分开。
每一个命令都是一个操作:请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作。
请求方和接收方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。
使请求本身成为一个对象,这个对象和其它对象一样可以被存储和传递。
命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。

4.使用场景
当需要对行为进行“记录、撤销/重做”等处理时。
系统需要将请求者和接收者解耦,使得调用者和接收者不直接交互。
系统需要在不同时间指定请求、请求排队和执行请求。
系统需要将一组操作组合在一起,即支持宏命令。

5.优缺点
优点:
解除了请求者与实现者之间的耦合,降低了系统的耦合度。
对请求排队或记录请求日志,支持撤销操作。
可以容易地设计一个组合命令。
新命令可以容易地加入到系统中。

缺点:
因为针对每一个命令都需要设计一个具体命令类,使用命令模式可能会导致系统有过多的具体命令类。

应用举例:银行帐号的存款、提款
UML图

代码实现
#include <list>#include <iostream>using namespace std;#define SAFE_RELEASE(_p){ if((_p)){ delete (_p); (_p) = NULL;} }class Account{public:Account(long account = 0) : m_totalAmount(account) {}void MoneyIn(long amount) { m_totalAmount += amount; }void MoneyOut(long amount) { m_totalAmount -= amount; }long GetTotalAmount() { return m_totalAmount; }private:long m_totalAmount;};class Command{public:Command(Account* account) { m_account = account; }virtual void ExecuteCommand() = 0;protected:Account*m_account;};class MoneyInCmd : public Command{public:MoneyInCmd(Account* account, long amount) : Command(account) { m_amount = amount; }virtual void ExecuteCommand() { m_account->MoneyIn(m_amount); }private:longm_amount;};class MoneyOutCmd : public Command{public:MoneyOutCmd(Account* account, long amount) : Command(account) { m_amount = amount; }virtual void ExecuteCommand() { m_account->MoneyOut(m_amount); }private:longm_amount;};class Invoker{public:void SetCommand(Command* command) { m_cmdlist.push_back(command);}void ExecuteCommand(){for (list<Command*>::iterator iter = m_cmdlist.begin(); iter != m_cmdlist.end(); iter++){(*iter)->ExecuteCommand();}}void UndoCommand(Command* command){for (list<Command*>::iterator iter = m_cmdlist.begin(); iter != m_cmdlist.end(); ){if (command == *iter)iter = m_cmdlist.erase(iter);elseiter++;}}private:list<Command*> m_cmdlist;};int main(){Account* pAccount = new Account(1000);//开通一个账户,里面预存1000块Command* pCommandIn = new MoneyInCmd(pAccount, 200);//向账户pAccount中存入200块Command* pCommandOut = new MoneyOutCmd(pAccount, 500);//从账户pAccount中取出500块Invoker* pInvoker = new Invoker();pInvoker->SetCommand(pCommandIn);pInvoker->SetCommand(pCommandOut);pInvoker->UndoCommand(pCommandIn);pInvoker->ExecuteCommand();cout<<pAccount->GetTotalAmount()<<endl;SAFE_RELEASE(pAccount);SAFE_RELEASE(pCommandIn);SAFE_RELEASE(pCommandOut);SAFE_RELEASE(pInvoker); return 0;}


原创粉丝点击