命令模式:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。

命令(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。

另外回调函数和命令模式还是有区别的,首先命令作为类对象,它的方法更多一些;其次,命令对象可以做撤回操作