类图
定义
将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其它对象。命令模式也支持可撤销的操作
优缺点
优点:
1.降低对象之间的耦合度。
2.新的命令可以很容易地加入到系统中。
3.可以比较容易地设计一个组合命令。
4.调用同一方法实现不同的功能
缺点:
使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。
适用环境:
1.系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
2.系统需要在不同的时间指定请求、将请求排队和执行请求。
3.系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
4.系统需要将一组操作组合在一起,即支持宏命令。
设计原则
多用组合,少用继承
针对接口编程,不针对实现编程
对交互对象之间松耦合设计而努力
类应该对扩展开放,对修改关闭
依赖抽象,不要依赖具体类
代码
RemoteControlWithUndo类:
#ifndef REMOTECONTROLWITHUNDO_H
#define REMOTECONTROLWITHUNDO_H
#include "command.h"
#include "nocommand.h"
#include <QVector>
class RemoteControlWithUndo
{
public:
RemoteControlWithUndo();
void setCommand(int slot, Command *onCommand, Command *offCommand);
void onButtonWasPushed(int slot);
void offButtonWasPushed(int slot);
void undoButtonWasPushed();
QString toString();
QVector<Command *> onCommands;
QVector<Command *> offCommands;
Command *undoCommand;
};
#endif // REMOTECONTROLWITHUNDO_H
#include "remotecontrolwithundo.h"
RemoteControlWithUndo::RemoteControlWithUndo()
{
Command *noCommand1 = new NoCommand();
Command *noCommand2 = new NoCommand();
Command *noCommand3 = new NoCommand();
onCommands.append(noCommand1);
onCommands.append(noCommand2);
onCommands.append(noCommand3);
Command *noCommand4 = new NoCommand();
Command *noCommand5 = new NoCommand();
Command *noCommand6 = new NoCommand();
offCommands.append(noCommand4);
offCommands.append(noCommand5);
offCommands.append(noCommand6);
Command *noCommand7 = new NoCommand();
undoCommand = noCommand7;
}
void RemoteControlWithUndo::setCommand(int slot, Command *onCommand, Command *offCommand)
{
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
void RemoteControlWithUndo::onButtonWasPushed(int slot)
{
if(onCommands.at(slot) != nullptr) {
onCommands.at(slot)->execute();
undoCommand = onCommands[slot];
}
}
void RemoteControlWithUndo::offButtonWasPushed(int slot)
{
if(offCommands.at(slot) != nullptr) {
offCommands.at(slot)->execute();
undoCommand = offCommands[slot];
}
}
void RemoteControlWithUndo::undoButtonWasPushed()
{
undoCommand->undo();
}
QString RemoteControlWithUndo::toString()
{
QString stringBuff;
stringBuff = "---------- Remote Control ----------/n";
for(int i = 0; i < onCommands.size(); i++) {
stringBuff += "[slot " + QString::number(i) +"] " +
onCommands.at(i)->getName() + " " +
offCommands.at(i)->getName() + "/n";
}
return stringBuff;
}
RemoteConrol类:
#ifndef REMOTECONROL_H
#define REMOTECONROL_H
#include "command.h"
#include "nocommand.h"
#include <QVector>
class RemoteConrol
{
public:
RemoteConrol();
void setCommand(int slot, Command *onCommand, Command *offCommand);
void onButtonWasPushed(int slot);
void offButtonWasPushed(int slot);
QString toString();
QVector<Command *> onCommands;
QVector<Command *> offCommands;
};
#endif // REMOTECONROL_H
#include "remoteconrol.h"
RemoteConrol::RemoteConrol()
{
Command *noCommand1 = new NoCommand();
Command *noCommand2 = new NoCommand();
Command *noCommand3 = new NoCommand();
onCommands.append(noCommand1);
onCommands.append(noCommand2);
onCommands.append(noCommand3);
Command *noCommand4 = new NoCommand();
Command *noCommand5 = new NoCommand();
Command *noCommand6 = new NoCommand();
offCommands.append(noCommand4);
offCommands.append(noCommand5);
offCommands.append(noCommand6);
}
void RemoteConrol::setCommand(int slot, Command *onCommand, Command *offCommand)
{
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
void RemoteConrol::onButtonWasPushed(int slot)
{
if(onCommands.at(slot) != nullptr) {
onCommands.at(slot)->execute();
}
}
void RemoteConrol::offButtonWasPushed(int slot)
{
if(offCommands.at(slot) != nullptr) {
offCommands.at(slot)->execute();
}
}
QString RemoteConrol::toString()
{
QString stringBuff;
stringBuff = "---------- Remote Control ----------/n";
for(int i = 0; i < onCommands.size(); i++) {
stringBuff += "[slot " + QString::number(i) +"] " +
onCommands.at(i)->getName() + " " +
offCommands.at(i)->getName() + "/n";
}
return stringBuff;
}
SimpleRemoteControl类:
#ifndef SIMPLEREMOTECONTROL_H
#define SIMPLEREMOTECONTROL_H
#include "command.h"
class SimpleRemoteControl
{
public:
SimpleRemoteControl();
void setCommandControl(Command* command);
void buttonWasPressed();
Command* slot;
};
#endif // SIMPLEREMOTECONTROL_H
#include "simpleremotecontrol.h"
SimpleRemoteControl::SimpleRemoteControl()
{
}
void SimpleRemoteControl::setCommandControl(Command* command)
{
slot = command;
}
void SimpleRemoteControl::buttonWasPressed()
{
slot->execute();
}
Command类:
#ifndef COMMAND_H
#define COMMAND_H
#include <QString>
class Command
{
public:
virtual void execute() = 0;
virtual void undo() = 0;
virtual QString getName();
QString name;
};
#endif // COMMAND_H
#include "command.h"
QString Command::getName()
{
return name;
}
NoCommand类:
#ifndef NOCOMMAND_H
#define NOCOMMAND_H
#include "command.h"
class NoCommand : public Command
{
public:
NoCommand();
void execute() override;
void undo() override;
};
#endif // NOCOMMAND_H
#include "nocommand.h"
NoCommand::NoCommand()
{
}
void NoCommand::execute()
{
}
void NoCommand::undo()
{
}
Light类:
#ifndef LIGHT_H
#define LIGHT_H
#include <QString>
class Light
{
public:
Light(QString name);
void on();
void off();
private:
QString name;
};
#endif // LIGHT_H
#include "light.h"
#include <QDebug>
Light::Light(QString name)
{
this->name = name;
}
void Light::on()
{
qDebug() << name + "Light is on";
}
void Light::off()
{
qDebug() << name + "Light is off";
}
LightOffCommand 类:
#ifndef LIGHTOFFCOMMAND_H
#define LIGHTOFFCOMMAND_H
#include "command.h"
#include "light.h"
class LightOffCommand : public Command
{
public:
LightOffCommand(Light* light);
void execute() override;
void undo() override;
private:
Light* light;
};
#endif // LIGHTOFFCOMMAND_H
#include "lightoffcommand.h"
LightOffCommand::LightOffCommand(Light* light)
{
this->light = light;
name = "light";
}
void LightOffCommand::execute()
{
light->off();
}
void LightOffCommand::undo()
{
light->on();
}
LightOnCommand类:
#ifndef LIGHTONCOMMAND_H
#define LIGHTONCOMMAND_H
#include "command.h"
#include "light.h"
class LightOnCommand : public Command
{
public:
LightOnCommand(Light* light);
void execute() override;
void undo() override;
Light* light;
};
#endif // LIGHTONCOMMAND_H
#include "lightoncommand.h"
LightOnCommand::LightOnCommand(Light* light)
{
this->light = light;
name = "light";
}
void LightOnCommand::execute()
{
light->on();
}
void LightOnCommand::undo()
{
light->off();
}
Stereo类:
#ifndef STEREO_H
#define STEREO_H
#include <QString>
class Stereo
{
public:
Stereo(QString name);
void on();
void off();
void setCD();
void setVolume(int volume);
private:
QString name;
};
#endif // STEREO_H
#include "stereo.h"
#include <QDebug>
Stereo::Stereo(QString name)
{
this->name = name;
}
void Stereo::on()
{
qDebug() << name + "Stereo is on";
}
void Stereo::off()
{
qDebug() << name + "Stereo is off";
}
void Stereo::setCD()
{
qDebug() << name + "Stereo is setCD";
}
void Stereo::setVolume(int volume)
{
qDebug() << name + "Stereo volume set to " + QString::number(volume);
}
StereoOffCommand 类:
#ifndef STEREOOFFCOMMAND_H
#define STEREOOFFCOMMAND_H
#include "command.h"
#include "stereo.h"
class StereoOffCommand : public Command
{
public:
StereoOffCommand(Stereo *stereo);
void execute() override;
void undo() override;
private:
Stereo *stereo;
};
#endif // STEREOOFFCOMMAND_H
#include "stereooffcommand.h"
StereoOffCommand::StereoOffCommand(Stereo *stereo)
{
this->stereo = stereo;
name = "stereo";
}
void StereoOffCommand::execute()
{
stereo->off();
}
void StereoOffCommand::undo()
{
stereo->on();
}
StereoOnWithCDCommand 类:
#ifndef STEREOONWITHCDCOMMAND_H
#define STEREOONWITHCDCOMMAND_H
#include "command.h"
#include "stereo.h"
class StereoOnWithCDCommand : public Command
{
public:
StereoOnWithCDCommand(Stereo *stereo);
void execute() override;
void undo() override;
private:
Stereo *stereo;
};
#endif // STEREOONWITHCDCOMMAND_H
#include "stereoonwithcdcommand.h"
StereoOnWithCDCommand::StereoOnWithCDCommand(Stereo *stereo)
{
this->stereo = stereo;
name = "stereo";
}
void StereoOnWithCDCommand::execute()
{
stereo->on();
stereo->setVolume(11);
}
void StereoOnWithCDCommand::undo()
{
stereo->off();
}
CeilingFan类:
#ifndef CEILINGFAN_H
#define CEILINGFAN_H
#include <QString>
class CeilingFan
{
public:
CeilingFan(QString location);
void high();
void medium();
void low();
void off();
int getSpeed();
QString location;
int speed;
const int HIGH = 3;
const int MEDIUM = 2;
const int LOW = 1;
const int OFF = 0;
};
#endif // CEILINGFAN_H
#include "ceilingfan.h"
#include <QDebug>
CeilingFan::CeilingFan(QString location)
{
this->location = location;
}
void CeilingFan::high()
{
speed = HIGH;
qDebug() << location + "CeilingFan is high";
}
void CeilingFan::medium()
{
speed = MEDIUM;
qDebug() << location + "CeilingFan is medium";
}
void CeilingFan::low()
{
speed = LOW;
qDebug() << location + "CeilingFan is low";
}
void CeilingFan::off()
{
speed = OFF;
qDebug() << location + "CeilingFan is off";
}
int CeilingFan::getSpeed()
{
return speed;
}
CeilingFanHighCommand 类:
#ifndef CEILINGFANHIGHCOMMAND_H
#define CEILINGFANHIGHCOMMAND_H
#include "command.h"
#include "ceilingfan.h"
class CeilingFanHighCommand : public Command
{
public:
CeilingFanHighCommand(CeilingFan *ceilingFan);
void execute() override;
void undo() override;
private:
CeilingFan *ceilingFan;
int prevSpeed;
};
#endif // CEILINGFANHIGHCOMMAND_H
#include "ceilingfanhighcommand.h"
CeilingFanHighCommand::CeilingFanHighCommand(CeilingFan *ceilingFan)
{
this->ceilingFan = ceilingFan;
}
void CeilingFanHighCommand::execute()
{
prevSpeed = ceilingFan->getSpeed();
ceilingFan->high();
}
void CeilingFanHighCommand::undo()
{
if(prevSpeed == ceilingFan->HIGH) {
ceilingFan->high();
} else if(prevSpeed == ceilingFan->MEDIUM) {
ceilingFan->medium();
} else if(prevSpeed == ceilingFan->LOW) {
ceilingFan->low();
} else if(prevSpeed == ceilingFan->OFF) {
ceilingFan->off();
}
}
CeilingFanLowCommand 类:
#ifndef CEILINGFANLOWCOMMAND_H
#define CEILINGFANLOWCOMMAND_H
#include "command.h"
#include "ceilingfan.h"
class CeilingFanLowCommand : public Command
{
public:
CeilingFanLowCommand(CeilingFan *ceilingFan);
void execute() override;
void undo() override;
private:
CeilingFan *ceilingFan;
int prevSpeed;
};
#endif // CEILINGFANLOWCOMMAND_H
#include "ceilingfanlowcommand.h"
CeilingFanLowCommand::CeilingFanLowCommand(CeilingFan *ceilingFan)
{
this->ceilingFan = ceilingFan;
}
void CeilingFanLowCommand::execute()
{
prevSpeed = ceilingFan->getSpeed();
ceilingFan->low();
}
void CeilingFanLowCommand::undo()
{
if(prevSpeed == ceilingFan->HIGH) {
ceilingFan->high();
} else if(prevSpeed == ceilingFan->MEDIUM) {
ceilingFan->medium();
} else if(prevSpeed == ceilingFan->LOW) {
ceilingFan->low();
} else if(prevSpeed == ceilingFan->OFF) {
ceilingFan->off();
}
}
CeilingFanMediumCommand 类:
#ifndef CEILINGFANMEDIUMCOMMAND_H
#define CEILINGFANMEDIUMCOMMAND_H
#include "command.h"
#include "ceilingfan.h"
class CeilingFanMediumCommand : public Command
{
public:
CeilingFanMediumCommand(CeilingFan *ceilingFan);
void execute() override;
void undo() override;
private:
CeilingFan *ceilingFan;
int prevSpeed;
};
#endif // CEILINGFANMEDIUMCOMMAND_H
#include "ceilingfanmediumcommand.h"
CeilingFanMediumCommand::CeilingFanMediumCommand(CeilingFan *ceilingFan)
{
this->ceilingFan = ceilingFan;
}
void CeilingFanMediumCommand::execute()
{
prevSpeed = ceilingFan->getSpeed();
ceilingFan->medium();
}
void CeilingFanMediumCommand::undo()
{
if(prevSpeed == ceilingFan->HIGH) {
ceilingFan->high();
} else if(prevSpeed == ceilingFan->MEDIUM) {
ceilingFan->medium();
} else if(prevSpeed == ceilingFan->LOW) {
ceilingFan->low();
} else if(prevSpeed == ceilingFan->OFF) {
ceilingFan->off();
}
}
CeilingFanOffCommand类:
#ifndef CEILINGFANOFFCOMMAND_H
#define CEILINGFANOFFCOMMAND_H
#include "command.h"
#include "ceilingfan.h"
class CeilingFanOffCommand : public Command
{
public:
CeilingFanOffCommand(CeilingFan *ceilingFan);
void execute() override;
void undo() override;
private:
CeilingFan *ceilingFan;
int prevSpeed;
};
#endif // CEILINGFANOFFCOMMAND_H
#include "ceilingfanoffcommand.h"
CeilingFanOffCommand::CeilingFanOffCommand(CeilingFan *ceilingFan)
{
this->ceilingFan = ceilingFan;
}
void CeilingFanOffCommand::execute()
{
prevSpeed = ceilingFan->getSpeed();
ceilingFan->off();
}
void CeilingFanOffCommand::undo()
{
if(prevSpeed == ceilingFan->HIGH) {
ceilingFan->high();
} else if(prevSpeed == ceilingFan->MEDIUM) {
ceilingFan->medium();
} else if(prevSpeed == ceilingFan->LOW) {
ceilingFan->low();
} else if(prevSpeed == ceilingFan->OFF) {
ceilingFan->off();
}
}
测试:
#include "mainwindow.h"
#include "simpleremotecontrol.h"
#include "light.h"
#include "lightoncommand.h"
#include "lightoffcommand.h"
#include "remoteconrol.h"
#include "stereo.h"
#include "stereoonwithcdcommand.h"
#include "stereooffcommand.h"
#include "remotecontrolwithundo.h"
#include "ceilingfan.h"
#include "ceilingfanhighcommand.h"
#include "ceilingfanmediumcommand.h"
#include "ceilingfanlowcommand.h"
#include "ceilingfanoffcommand.h"
#include "macrocommand.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// 1.
// SimpleRemoteControl *remote = new SimpleRemoteControl();
// Light *light = new Light();
// LightOnCommand *lightOn = new LightOnCommand(light);
// remote->setCommandControl(lightOn);
// remote->buttonWasPressed();
// 2.
// RemoteConrol *remoteConrol = new RemoteConrol();
// Light *livingRoomLight = new Light("Living Room");
// Light *kitchenLight = new Light("kitchen");
// Stereo *stereo = new Stereo("Living Room");
// LightOnCommand *livingRoomLightOn = new LightOnCommand(livingRoomLight);
// LightOffCommand *livingRoomLightOff = new LightOffCommand(livingRoomLight);
// LightOnCommand *kitchenLightOn = new LightOnCommand(kitchenLight);
// LightOffCommand *kitchenLightOff = new LightOffCommand(kitchenLight);
// StereoOnWithCDCommand *stereoOnWithCD = new StereoOnWithCDCommand(stereo);
// StereoOffCommand *stereoOff = new StereoOffCommand(stereo);
// remoteConrol->setCommand(0, livingRoomLightOn, livingRoomLightOff);
// remoteConrol->setCommand(1, kitchenLightOn, kitchenLightOff);
// remoteConrol->setCommand(2, stereoOnWithCD, stereoOff);
// qDebug() << remoteConrol->toString();
// remoteConrol->onButtonWasPushed(0);
// remoteConrol->offButtonWasPushed(0);
// remoteConrol->onButtonWasPushed(1);
// remoteConrol->offButtonWasPushed(1);
// remoteConrol->onButtonWasPushed(2);
// remoteConrol->offButtonWasPushed(2);
// 3.
// RemoteControlWithUndo *remoteControl = new RemoteControlWithUndo();
// Light *livingRoomLight = new Light("Living Room");
// LightOnCommand *livingRoomLightOn = new LightOnCommand(livingRoomLight);
// LightOffCommand *livingRoomLightOff = new LightOffCommand(livingRoomLight);
// remoteControl->setCommand(0, livingRoomLightOn, livingRoomLightOff);
// remoteControl->onButtonWasPushed(0);
// remoteControl->offButtonWasPushed(0);
// qDebug() << remoteControl->toString();
// remoteControl->undoButtonWasPushed();
// remoteControl->offButtonWasPushed(0);
// remoteControl->onButtonWasPushed(0);
// qDebug() << remoteControl->toString();
// remoteControl->undoButtonWasPushed();
// 4.
// RemoteControlWithUndo *remoteControl = new RemoteControlWithUndo();
// CeilingFan *ceilingFan = new CeilingFan("Living Room");
// CeilingFanMediumCommand *ceilingFanMedium = new CeilingFanMediumCommand(ceilingFan);
// CeilingFanHighCommand *ceilingFanHigh = new CeilingFanHighCommand(ceilingFan);
// CeilingFanOffCommand *ceilingFanOff = new CeilingFanOffCommand(ceilingFan);
// remoteControl->setCommand(0, ceilingFanMedium, ceilingFanOff);
// remoteControl->setCommand(1, ceilingFanHigh, ceilingFanOff);
// remoteControl->onButtonWasPushed(0);
// remoteControl->offButtonWasPushed(0);
// qDebug() << remoteControl->toString();
// remoteControl->undoButtonWasPushed();
// remoteControl->onButtonWasPushed(1);
// qDebug() << remoteControl->toString();
// remoteControl->undoButtonWasPushed();
// 5.
RemoteControlWithUndo *remoteControl = new RemoteControlWithUndo();
Light *livingRoomLight = new Light("Living Room");
Stereo *stereo = new Stereo("Living Room");
LightOnCommand *livingRoomLightOn = new LightOnCommand(livingRoomLight);
LightOffCommand *livingRoomLightOff = new LightOffCommand(livingRoomLight);
StereoOnWithCDCommand *stereoOnWithCD = new StereoOnWithCDCommand(stereo);
StereoOffCommand *stereoOff = new StereoOffCommand(stereo);
QVector<Command *> partyOn;
partyOn.append(livingRoomLightOn);
partyOn.append(stereoOnWithCD);
QVector<Command *> partyOff;
partyOff.append(livingRoomLightOff);
partyOff.append(stereoOff);
MacroCommand *partyOnMacro = new MacroCommand(partyOn);
MacroCommand *partyOffMacro = new MacroCommand(partyOff);
remoteControl->setCommand(0, partyOnMacro, partyOffMacro);
qDebug() << remoteControl->toString();
remoteControl->onButtonWasPushed(0);
remoteControl->offButtonWasPushed(0);
}
MainWindow::~MainWindow()
{
}