设计模式(七):命令模式

  命令模式的定义:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

  怎么理解呢,举个遥控器的例子,但是这个 遥控器上面的按钮,跟普通不一样。简单来说,就是有分别控制电视开关,电灯开关,风扇开关,空调开关等的按钮。普通情况下,如果你对遥控器编程,那么就会通过遥控器对象,来分别调用电视对象的开关方法,或者风扇对象的开关方法,或者空调对象的开关方法。这样,就会有个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方法。

原文地址:https://www.cnblogs.com/bracken/p/3019413.html