《Head First 设计模式》例子的C++实现(6 命令模式)

#《Head First 设计模式》例子的C++实现(6 命令模式)

命令模式也是比较简单的模式。通常我们一个对象可能会有几十个对外的接口。我们要操作许多不同的对象时无法将这些对象搞成同样的接口。那么这时就可以一个单一的命令接口类。这个接口类作为桥梁,连接其他对象的某一个动作。

这个设计模式主要的缺点是会引入大量的类,每个类只实现一小点功能。

接口类可以设计成如下的样子:

class Command
{
public:
    Command()
    {
    }

    virtual ~Command()
    {
    }

    virtual void execute() = 0;
    virtual void undo() = 0;
};

比如我们有个音响,这个音响有许多功能。比如下面这样。

class Stereos
{
public:
    Stereos()
    {

    }

    void on()
    {
        qDebug() << "   Living Room Stereos is on";
    }

    void off()
    {
        qDebug() << "   Living Room Stereos is off";
    }

    void setCD()
    {
        qDebug() << "   Living Room Stereos is set for CD input";
    }

    void setVolume()
    {
        qDebug() << "   Living Room Stereos volume set to 10";
    }
};

还有好几个灯,这些灯有个统一的接口。

class Light
{
public:
    Light()
    {

    }

    virtual ~Light()
    {

    }

    virtual void on() = 0;
    virtual void off() = 0;
};

class CeillingLight : public Light
{
public:
    CeillingLight()
    {

    }

    void on() override
    {
        qDebug() << "   Ceilling Light is on";
    }

    void off() override
    {
        qDebug() << "   Ceilling Light is off";
    }
};

class OutdoorLight : public Light
{
public:
    OutdoorLight()
    {

    }

    void on() override
    {
        qDebug() << "   Outdoor Light is on";
    }

    void off() override
    {
        qDebug() << "   Outdoor Light is off";
    }
};

可以看到这几个类的接口完全不同。那么如何把这些类统一成一样的接口呢。我们可以利用我们刚才给出的接口类 Command。

class StereosOffWithCdCommand : public Command
{
public:
    StereosOffWithCdCommand(Stereos * stereos)
    {
        m_stereos = stereos;
    }

    ~StereosOffWithCdCommand() override
    {

    }

    void execute() override
    {
        m_stereos->off();
    }

    void undo() override
    {
        m_stereos->on();
        m_stereos->setCD();
        m_stereos->setVolume();
    }

private:
    Stereos * m_stereos;
};

class StereosOnWithCdCommand : public Command
{
public:
    StereosOnWithCdCommand(Stereos * stereos)
    {
        m_stereos = stereos;
    }

    ~StereosOnWithCdCommand() override
    {

    }

    void execute() override
    {
        m_stereos->on();
        m_stereos->setCD();
        m_stereos->setVolume();
    }

    void undo() override
    {
        m_stereos->off();
    }

private:
    Stereos * m_stereos;
};

对于各个灯也类似处理:

class LightOffCommand : public Command
{
public:
    LightOffCommand(Light * light)
    {
        m_light = light;
    }

    ~LightOffCommand() override
    {

    }

    void execute() override
    {
        m_light->off();
    }

    void undo() override
    {
        m_light->on();
    }
private:
    Light * m_light;
};

class LightOnCommand : public Command
{
public:
    LightOnCommand(Light * light)
    {
        m_light = light;
    }

    ~LightOnCommand() override
    {

    }

    void execute() override
    {
        m_light->on();
    }

    void undo() override
    {
        m_light->off();
    }
private:
    Light * m_light;
};

除此之外,我们还可以实现个空命令。当没有命令可以执行时就执行这个。

class NoCommand : public Command
{
public:
    NoCommand()
    {

    }

    ~NoCommand() override
    {

    }

    void execute() override
    {
        qDebug() << "   No Command";
    }

    void undo() override
    {
        qDebug() << "   No Command";
    }
};

下面时遥控器的代码:

class RemoteControl
{
public:
    RemoteControl();
    ~RemoteControl();
    void setCommand(int pos, Command * onCommand, Command * offCommand);
    void onButtonWasPushed(int pos);
    void offButtonWasPushed(int pos);
    void undoButtonWasPushed();
private:
    NoCommand m_noCommand[10];
    Command * m_onCommand[5];
    Command * m_offCommand[5];
    Command * m_undoCommand;
};

RemoteControl::RemoteControl()
{
    for(int i = 0; i < 5; i++)
    {
        m_onCommand[i] = &m_noCommand[i];
        m_offCommand[i] = &m_noCommand[i+5];
    }
}

RemoteControl::~RemoteControl()
{

}

void RemoteControl::setCommand(int pos, Command * onCommand, Command * offCommand)
{
    m_onCommand[pos] = onCommand;
    m_offCommand[pos] = offCommand;
}

void RemoteControl::onButtonWasPushed(int pos)
{
    if(pos < 5 && pos >= 0)
    {
        m_onCommand[pos]->execute();
        m_undoCommand = m_onCommand[pos];
    }

}

void RemoteControl::offButtonWasPushed(int pos)
{
    if(pos < 5 && pos >= 0)
    {
        m_offCommand[pos]->execute();
        m_undoCommand = m_offCommand[pos];
    }
}

void RemoteControl::undoButtonWasPushed()
{
    m_undoCommand->undo();
}

下面是测试代码:

扫描二维码关注公众号,回复: 3760680 查看本文章
    RemoteControl * m_remoteControl = new RemoteControl;

    Light * m_outdoorLight = new OutdoorLight;
    Light * m_ceillingLight = new CeillingLight;
    Stereos * m_stereos = new Stereos;

    Command * m_outdoorLightOn = new LightOnCommand(m_outdoorLight);
    Command * m_outdoorLightOff = new LightOffCommand(m_outdoorLight);
    Command * m_ceillingLightOn = new LightOnCommand(m_ceillingLight);
    Command * m_ceillingLightOff = new LightOffCommand(m_ceillingLight);

    Command * m_stereosOnWithCdCommand = new StereosOnWithCdCommand(m_stereos);
    Command * m_stereosOffWithCdCommand = new StereosOffWithCdCommand(m_stereos);

    m_remoteControl->setCommand(0, m_outdoorLightOn, m_outdoorLightOff);
    m_remoteControl->setCommand(1, m_ceillingLightOn, m_ceillingLightOff);
    m_remoteControl->setCommand(3, m_stereosOnWithCdCommand, m_stereosOffWithCdCommand);

    for(int i = 0; i < 5; i++)
    {
        qDebug() << "The Number " << i << " ON Button Was Pushed : ";
        m_remoteControl->onButtonWasPushed(i);
        qDebug() << "The Number " << i << " OFF Button Was Pushed : ";
        m_remoteControl->offButtonWasPushed(i);
        qDebug() << "Undo Button Was Pushed : ";
        m_remoteControl->undoButtonWasPushed();
        qDebug() << "";
    }

    delete m_remoteControl;
    delete m_outdoorLight;
    delete m_ceillingLight;
    delete m_stereos;

输出的结果如下:

The Number  0  ON Button Was Pushed :
   Outdoor Light is on
The Number  0  OFF Button Was Pushed :
   Outdoor Light is off
Undo Button Was Pushed :
   Outdoor Light is on

The Number  1  ON Button Was Pushed :
   Ceilling Light is on
The Number  1  OFF Button Was Pushed :
   Ceilling Light is off
Undo Button Was Pushed :
   Ceilling Light is on

The Number  2  ON Button Was Pushed :
   No Command
The Number  2  OFF Button Was Pushed :
   No Command
Undo Button Was Pushed :
   No Command

The Number  3  ON Button Was Pushed :
   Living Room Stereos is on
   Living Room Stereos is set for CD input
   Living Room Stereos volume set to 10
The Number  3  OFF Button Was Pushed :
   Living Room Stereos is off
Undo Button Was Pushed :
   Living Room Stereos is on
   Living Room Stereos is set for CD input
   Living Room Stereos volume set to 10

The Number  4  ON Button Was Pushed :
   No Command
The Number  4  OFF Button Was Pushed :
   No Command
Undo Button Was Pushed :
   No Command

猜你喜欢

转载自blog.csdn.net/liyuanbhu/article/details/83473109