C++ 设计模式之命令模式
简介
1、命令模式 (Command)是一种行为型设计模式,它将一个请求封装为一个对象,从而使您可以用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
2、命令模式 (Command)应用场景包括但不限于:
2.1、需要将请求调用者和请求接收者解耦时。
2.2、需要支持撤销(Undo)和重做(Redo)操作时。
2.3、当系统需要支持命令的排队执行和历史记录功能时。
2.4、当系统需要组合命令,形成宏命令时。
3、命令模式 (Command)的构成
3.1、命令接口
class Command
{
public:virtual ~Command() {};virtual void execute() = 0;
};
3.2、具体命令
class Light
{
public:void on();void off();
};
3.3、命令执行对象
class LightOnCommand : public Command
{
public:LightOnCommand(Light& li);void execute();
private:Light& light;
};
4、命令模式 (Command)的优点
4.1、解耦:调用方(客户端)和接收方(接收器)之间没有直接关系,双方只通过命令对象进行通信,更易于维护和扩展。
4.2、扩展性:新增命令或者改变命令的实现不会影响现有的其他类,符合开闭原则。
4.3、组合命令:可以将多个简单命令组合成一个复合命令(宏命令),方便执行多个操作。
4.4、支持撤销/重做:命令通常可以做到“可撤销”,容易实现操作的撤销和重做。
4.5、更好的控制:可以对命令进行排队和记录,以及在无需知道命令具体实现的情况下进行其他操作。
5、命令模式 (Command)的缺点
5.1、类膨胀:每个单独的命令都需要一个新的类进行包装,当命令多时类的数量会急剧增加。
5.2、复杂度增加:设计和实现更加复杂,特别是需要维护历史状态和相关状态回滚时。
简单示例
1、定义
// 命令接口
class Command
{
public:virtual ~Command() {};virtual void execute() = 0;
};// 具体命令
class Light
{
public:void on();void off();
};class LightOnCommand : public Command
{
public:LightOnCommand(Light& li);void execute();
private:Light& light;
};class LightOffCommand : public Command
{
public:LightOffCommand(Light& li);void execute();
private:Light& light;
};// 调用者
class SimpleRemoteControl
{
public:SimpleRemoteControl();void setCommand(Command* commend);void buttonWasPressed();private:Command* solt;
};
2、实现
void Light::on()
{std::cout << "Light is on" << std::endl;
}void Light::off()
{std::cout << "Light is off" << std::endl;
}LightOnCommand::LightOnCommand(Light& li) : light(li)
{}void LightOnCommand::execute()
{light.on();
}LightOffCommand::LightOffCommand(Light& li) : light(li)
{}void LightOffCommand::execute()
{light.off();
}SimpleRemoteControl::SimpleRemoteControl() : solt(nullptr)
{}void SimpleRemoteControl::setCommand(Command* commend)
{solt = commend;
}void SimpleRemoteControl::buttonWasPressed()
{if (solt){solt->execute();}
}
3、调用
SimpleRemoteControl si;
Light li;
LightOnCommand lightOn(li);
LightOffCommand lightOff(li);si.setCommand(&lightOn);
si.buttonWasPressed();si.setCommand(&lightOff);
si.buttonWasPressed();