#《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();
}
下面是测试代码:
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