命令模式
定义:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
类图
客户角色(Client): 创建具体的命令对象,并且设置命令对象的接收者。
命令角色(Command): 定义命令的接口,声明执行的方法。这是一个抽象类。
具体命令角色(ConcreteCommand):命令接口实现对象,是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
请求者角色(Invoker):要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
接收者角色(Receiver):接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
例子:
根据大多数例子就是 遥控器和饭店点餐,这里使用遥控器。
先看个 很丑的 遥控器图
根据介绍,命令模式是一个解耦的模式。
假设这个界面是遥控器,那么我们这些按钮执行的函数永远是一样的,不变的。
不会因为我想让第一个按钮打开 厨房灯,而却 更改 触发第一个按钮的内容。
请参照我上传的资源 (半夜上传没有审核啊,不知道百度网盘连接能用不:http://pan.baidu.com/s/1i5xzZKD)
来看 CommandPattern(1)
在这个遥控器例,我们的按钮槽函数永远不变:
void RemoteControl::on_pushButton_clicked()
{
m_pInvoker->doOnCommand(0);
}
void RemoteControl::on_pushButton_2_clicked()
{
m_pInvoker->doOffCommand(0);
}
void RemoteControl::on_pushButton_3_clicked()
{
m_pInvoker->doOnCommand(1);
}
void RemoteControl::on_pushButton_4_clicked()
{
m_pInvoker->doOffCommand(1);
}
...
...
void RemoteControl::on_pushButton_15_clicked()
{
m_pInvoker->doUndo();
}
那么我们怎么通过触发第一个按钮就实现 客厅开灯这个操作?
我们用一个类Invoker 来管理操作命令, 这里有两组 一个是开,一个是关。
Invoker.h
public:
NoCommand * m_pNoCommand; // 未定义命令
QVector<ICommand *> onCommands; // "开" 命令组
QVector<ICommand *> offCommands; // "关" 命令组
public:
// 设置遥控器 按键 对应的 开命令 关命令
void setCommand(int slot, ICommand *onCommand, ICommand *offCommand);
void doOnCommand(int slot); // "开" 命令 的执行
void doOffCommand(int slot); // "关" 命令 的执行
Invoker.cpp 具体实现:
Invoker::Invoker()
{
m_pNoCommand = new NoCommand;
// 初始化 开 关 两组命令
for(int i = 0; i < SLOTNUMBER; i++)
{
onCommands.push_back(m_pNoCommand);
offCommands.push_back(m_pNoCommand);
}
}
// 设置按钮对应命令 开 关
void Invo