什么是命令模式?
在GOF的《设计模式:可复用面向对象软件的基础》一书中对命令模式是这样说的:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。在OOP中,一切都是对象,将请求封装成对象,符合OOP的设计思想,当将客户的单个请求封装成对象以后,我们就可以对这个请求存储更多的信息,使请求拥有更多的能力;命令模式同样能够把请求发送者和接收者解耦,使得命令发送者不用去关心请求将以何种方式被处理。
我们在12306上,单击购票,这是一个请求,12306将这个请求封装为一个对象,在12306还没有上线排队系统时,你买票是这样的:你不停的用鼠标点击12306网站上的购票按钮,直到你买到了票;对于你的每一次点击,服务器都要进行处理,做出响应,告诉你,有没有买到票;这样,可能就会出现很多次无效的点击,但是这些无效的点击却增加了服务器的负担。增加了排队系统以后,你的购票请求就进入了对应的购票队列,一旦你进入了购票队列,当你再次鼠标单击购票时,12306会拒绝你的购票请求,它会告诉你,你已经进入了购票队列;处于购票队列中的你,你可以选择退出购票队列去购买其它车次的车票,从而进入其它购票队列。这样就有效的减少了购票者发送很多无效的购票请求。
这就好比票是共享资源,谁都想要,但是票的数量是一定的;在没有排队系统之前,大家的购票请求都是去竞争这个票,服务器对于大家对于共享资源——票的竞争进行互斥,谁抢到了,票就少一张;而现在有了购票队列以后,大家都不用去竞争了,按时间的先后顺序排好队,12306把票一张张的发给进入队列的购票者。
UML类图
角色用途:
客户(Client)角色:创建了一个具体命令(ConcreteCommand)对象并确定其接收者。
命令(Command)角色:声明了一个给所有具体命令类的抽象接口。这是一个抽象角色。
具体命令(ConcreteCommand)角色:定义一个接受者和行为之间的弱耦合;实现Execute()方法,负责调用接收考的相应操作。Execute()方法通常叫做执行方法。
请求者(Invoker)角色:负责调用命令对象执行请求,相关的方法叫做行动方法。
接收者(Receiver)角色:负责具体实施和执行一个请求。任何一个类都可以成为接收者,实施和执行请求的方法叫做行动方法。
实例:
#include<iostream>
#include<vector>
using namespace std;
//烤肉师傅,相当于Receiver
class RoastCook
{
public:
void MakeMutton()
{
cout << "烤羊肉" << endl;
}
void MakeChickenWing()
{
cout << "烤鸡翅膀" << endl;
}
};
//抽象命令类
class Command
{
public:
Command(RoastCook* temp)
{
receiver = temp;
}
virtual void ExecuteCmd() = 0;
protected:
RoastCook* receiver;
};
//烤羊肉命令
class MakeMuttonCmd :public Command
{
public:
MakeMuttonCmd(RoastCook* temp):Command(temp){}
virtual void ExecuteCmd() { receiver->MakeMutton(); }
};
//烤鸡翅命令
class MakeChickenWingCmd :public Command
{
public:
MakeChickenWingCmd(RoastCook* temp) :Command(temp) {}
virtual void ExecuteCmd() { receiver->MakeChickenWing(); }
};
//服务类,相当于invoker,将命令封装成一个命令对象保存起来,待到需要时执行
class Waiter
{
public:
void SetCmd(Command* temp)
{
m_commandList.push_back(temp); //将用户的请求封装成命令实体加入到vector队列中,模拟一个排队的过程
}
//通知执行
void Notify()
{
vector<Command*>::iterator it;
for (it = m_commandList.begin(); it != m_commandList.end(); ++it)
{
(*it)->ExecuteCmd();
}
}
private:
vector<Command*> m_commandList;
};
//客户端,client
int main(int argc,char* argv[])
{
//店里添加烤肉师傅,菜单,服务员等顾客
RoastCook* cook = new RoastCook();
Command* cmd1 = new MakeMuttonCmd(cook);
Command* cmd2 = new MakeChickenWingCmd(cook);
Waiter* girl = new Waiter();
//点菜
girl->SetCmd(cmd1);
girl->SetCmd(cmd2);
//服务员通知
girl->Notify();
return 0;
}
总结
命令模式是一个很经典的模式,我的理解也不会很到位;在我们的身边,就存在很多的使用命令模式的例子,数据库中的事务就是使用命令模式去实现的,在C#中的委托也是使用命令模式去实现的。我在这里只是将我在学习过程中理解到的东西记录了下来和大家分享。可能有的地方我的理解也存在差错,希望大家和我分享你对命令模式的理解。