命令模式的定义:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
怎么理解呢,举个遥控器的例子,但是这个 遥控器上面的按钮,跟普通不一样。简单来说,就是有分别控制电视开关,电灯开关,风扇开关,空调开关等的按钮。普通情况下,如果你对遥控器编程,那么就会通过遥控器对象,来分别调用电视对象的开关方法,或者风扇对象的开关方法,或者空调对象的开关方法。这样,就会有个if 语句来判断,是调用哪一个对象的方法。命令模式,就是将此时的开关电器的方法抽象出来,进行封装。只要遥控器中存放了开关电器的请求的对象就可以了。代码如下:
#include <iostream> #include <vector> #include <assert.h> using namespace std; enum pos { LIGHT_POSITION, CEILING_FAN_POSITION, GARAGE_DOOR_POSITION, STEREO_POSITION }; class Light { public: Light() : status( false ){} ~Light(){} void on() { status = true; } void off() { status = false; } bool GetLightStatus() { return status; } private: bool status; /* data */ }; class Command { public: Command(){} ~Command(){} virtual void excute(){} /* data */ }; class LightOnCommand : public Command { public: LightOnCommand( Light &li ) : light( &li ) {} ~LightOnCommand(){} void excute() { light->on(); } private: Light *light; /* data */ }; class LightOffCommand : public Command { public: LightOffCommand( Light &li ) : light( &li ) {} ~LightOffCommand(){} void excute() { light->off(); } private: Light *light; /* data */ }; class SimpleRemoteControl { public: SimpleRemoteControl(){} ~SimpleRemoteControl(){} void SetCommand( Command &lon, Command &lof ) { onCommand.push_back( &lon ); offCommand.push_back( &lof ); } void LightOnButtonWasPressed( int slot ) { onCommand[slot]->excute(); } void LightOffButtonWasPressed( int slot ) { offCommand[slot]->excute(); } private: vector<Command*> onCommand; vector<Command*> offCommand; /* data */ }; void TestLight() { Light light; light.on(); assert( true == light.GetLightStatus() ); } void TestCommandPartenLightOnCommand() { Light light; LightOnCommand lo( light ); lo.excute(); assert( true == light.GetLightStatus() ); LightOffCommand lof( light ); lof.excute(); assert( false == light.GetLightStatus() ); } void TestCommandParternClient() { Light light; LightOnCommand lon( light ); LightOffCommand lof( light ); SimpleRemoteControl simpleRemoteControl; simpleRemoteControl.SetCommand( lon, lof ); simpleRemoteControl.LightOnButtonWasPressed( LIGHT_POSITION ); assert( true == light.GetLightStatus() ); simpleRemoteControl.LightOffButtonWasPressed( LIGHT_POSITION ); assert( false == light.GetLightStatus() ); } void TestCommandParten() { TestLight(); TestCommandPartenLightOnCommand(); TestCommandParternClient(); } int main() { TestCommandParten(); return 0; }
其中,枚举的pos为各个电器的开关在遥控器上面的位置。Light为灯的类,其中实现了具体的打开方法on(),关闭方法off(),并且存储了目前的灯所处的状态。
接下来的command类为所有电器开关的父类,可以派生出各个电器开关请求的子类,如LightOnCommand和LightOnCommand两个子类。这两个子类接受电器实例作为初始化参数,excute方法调用电器实例的具体开关请求。
前面这部分,主要将电器实例的开关请求进行了封装,后续的操作只要针对command来操作就可以了,在程序执行过程中,会根据具体是哪个电器开关请求来动态调用哪个excute方法。
SimpleRemoteControl就是我们要的客户端类,即遥控器。遥控器中我们用vector来存储请求实例的指针,通过SetCommand方法来存入具体的电器开关请求。LightOnButtonWasPressed则在按下某个位置的按钮时,调用具体的excute方法。