命令(Command)模式
一、问题的提出
有一个遥控器有几个可编程的插槽(每个都可以控制不同的家电装置),每个插槽都有对应的开关按钮。同时开发厂商提供了一组类,用来控制家电装置。如电灯、电扇、音响等等。每个类都有相应了on、off和其他相应的方法。现在需要你能创建一组控制遥控器的API,让每个插槽都能控制一个或者一组装置。注意,能够控制目前的任何装置和任何未来可能出现的装置。
二、命令对象
将控制电器厂商类的方法(如on、off电灯)看成是命令对象,让所有的命令对象实现相同的接口。在前面工厂模式中词方法为orderUp,现在改为一般惯用的名称execute()。命令接口如下:
class Command
{
public:
virtual void execute() = 0;
};
现在,假设想实现一个打开电灯的命令。根据厂商提供的类,Light类有两个方法:on和off。下面将这个类的方式实现成一个命令:
class Light
{
public:
void on();
void off();
};
class LightOnCommand : public Command
{
public:
Light* light;
LightOnCommand(Light* light);//构造函数被传入某个电灯(如:客厅的电灯),以便让这个命令控制,
<span style="white-space:pre"> </span>//然后记录在实例变量中.一旦execute调用,经过动该绑定,
//就由这个传入的电灯对象成为命令的接收者,接收请求.
void execute();//这个execute方法调用接收对象(我们正在控制的电灯)的on方法.
};
cpp:
void Light::on()
{
cout<<"light on!"<<endl;
}
void Light::off()
{
coit<<"light off"<<endl;
}
void LightOnCommand::LightOnCommand(Light* light)
{
this->light = light;
}
void LightOnCommand::execute()
{
light->on();
}
把打开电灯的on方法调用封装进命令对象LightOnCommand,然后就可以使用这个命令对象实现功能。
假设有一个遥控器,它通过一个按钮控制一个装置:
.h
class SimpleRemoteControl
{
public:
Command* slot;//有个插槽持有命令,而这个命令控制一个装置
void setCommand(Command* command); //这个方法用来设置命令.如果这段代码的客户想要多次改变遥控器按钮的行为,
//可以多次调用这个方法
void ButtonPressed();//按下按钮时,这个方法被调用,使得当前命令衔接的插槽,并调用它的execute()方法.
};
.cpp
void SimpleRemoteControl::setCommand(Command* command)
{
this->slot = command;
}
void SimpleRemoteControl::ButtonPressed()
{
slot->execute();//动态绑定
}
测试:
SimpleRemoteControl* remote = new SimpleRemoteControl();//创建遥控器,就是调用者
Light* light = new Light();//创建点等对象,次对象就是命令请求的接受者
LightOnCommand* lightOn = new LightOnCommand(light);//创建一个命令,然后将接受者传给它
remote->setCommand(lightOn);//把命令传给调用者
remote->ButtonPressed();//模拟按下按钮
delete remote;
delete light;
delete lightOn;
三、定义命令模式
命令模式将“请求”(函数调用)封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
一个命令对象通过在特定的命令接收者上绑定一组操作来封装一个请求。要达到这一点,命令对象将动作和接收者包进对象中。这个对象只暴露出一个execute()方法,当此方法被调用的时候,接收者就会进行这些动作。从外面来看,其他对象不知道究竟哪个接收者进行了哪些动作,只知道如果调用execute()方法,请求的目的就能达到。
工厂模式把对象创建封装起来,命令模式把方法调用封装起来