C++实现命令模式Command Pattern

命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。

命令模式将发出请求的对象和执行请求的对象解耦。

在被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接收者和一个或一组动作。

调用者通过调用命令对象的execute()发出请求,这会使得接收者的动作被调用。

调用者可以接受命令当作参数,甚至在运行时动态地进行。

命令可以支持撤销,做法是实现一个undo()方法来回到execute()被执行前的状态。

宏命令是命令的一种简单的延伸,允许调用多个命令。

命令也可以用来实现日志和事务系统。


命令可以将运算快打包(一个接收者一组动作),然后将它传来传去,就像是一般的对象一样。现在,即使在命令对象被创建许久之后,运算依然可以被调用。事实上,它甚至可以在不同的线程中被调用。我们可以利用这样的特性衍生一些应用,例如:日程安排(Scheduler)、线程池、工作队列等。

某些应用需要我们将所有的动作都记录在日志中,并能在系统死机之后,重新调用这些动作恢复到之前的状态。通过新增两个方法(store()、load()),命令模式就能够支持这一点。

当我们执行命令的时候,将历史记录储存在磁盘中。一旦系统死机,我们就可以将命令对象重新加载,并成批地依次调用这些对象的execute()方法。

比方说,对于电子表格应用,我们可能想要实现的 错误恢复方式是将电子表格的才做记录在日志中,而不是每次电子表格一有变化就记录整个电子表格。


五花八门的厂商类

#include <iostream>
#include <string>
#include <vector>

class Light {
private:
	std::string location;
	int level;
public:
	Light(std::string loc) {
		location = loc;
	}
	void on() {
		level = 100;
		printf("Light is on\n");
	}
	void off() {
		level = 0;
		printf("Light is off\n");
	}
	void dim(int le) {
		level = le;
		if (level == 0) {
			off();
		}
		else {
			printf("Light is dimmed to %d %%\n", level);
		}
	}
	int getLevel() {
		return level;
	}
};

class CeilingFan {
private:
	std::string location = "";
	int level;
public:
	static const int HIGH = 3;
	static const int MEDIUM = 2;
	static const int LOW = 1;
	static const int OFF = 0;
	CeilingFan(std::string loc) {
		location = loc;
		level = OFF;
	}
	void high() {
		// turns the ceiling fan on to high
		level = HIGH;
		printf("%s ceiling fan is on high\n", location.c_str());

	}
	void medium() {
		// turns the ceiling fan on to medium
		level = MEDIUM;
		printf("%s ceiling fan is on medium\n", location.c_str());
	}
	void low() {
		// turns the ceiling fan on to low
		level = LOW;
		printf("%s ceiling fan is on low\n", location.c_str());
	}
	void off() {
		// turns the ceiling fan off
		level = OFF;
		printf("%s ceiling fan is off\n", location.c_str());
	}
	int getSpeed() {
		return level;
	}
};

class GarageDoor {
private:
	std::string location;
public:
	GarageDoor(std::string loc) {
		location = loc;
	}
	void up() {
		printf("%s garage Door is Up\n", location.c_str());
	}
	void down() {
		printf("%s garage Door is Down\n", location.c_str());
	}
	void stop() {
		printf("%s garage Door is Stopped\n", location.c_str());
	}
	void lightOn() {
		printf("%s garage light is on\n", location.c_str());
	}
	void lightOff() {
		printf("%s garage light is off\n", location.c_str());
	}
};

class Stereo {
private:
	std::string location;
public:
	Stereo(std::string loc) {
		location = loc;
	}
	void on() {
		printf("%s stereo is on\n", location.c_str());
	}
	void off() {
		printf("%s stereo is off\n", location.c_str());
	}
	void setCD() {
		printf("%s stereo is set for CD input\n", location.c_str());
	}
	void setDVD() {
		printf("%s stereo is set for DVD input\n", location.c_str());
	}
	void setRadio() {
		printf("%s stereo is set for Radio\n", location.c_str());
	}
	void setVolume(int volume) {
		// code to set the volume
		// valid range: 1-11 (after all 11 is better than 10, right?)
		printf("%s stereo volume set to %d\n", location.c_str(), volume);
	}
};

定义命令接口

class Command {
public:
	virtual void execute() = 0;
	virtual void undo() = 0;
};

实现成命令

class LightOnCommand :public Command {
private:
	Light *light;
public:
	LightOnCommand(Light *li) {
		light = li;
	}
	void execute() {
		light->on();
	}
	void undo() {
		light->off();
	}
};

class LightOffCommand :public Command {
private:
	Light* light;
public:
	LightOffCommand(Light* li) {
		light = li;
	}
	void execute() {
		light->off();
	}
	void undo() {
		light->on();
	}
};

class CeilingFanHighCommand :public Command {
private:
	CeilingFan* ceilingFan;
	int prevSpeed;
public:
	CeilingFanHighCommand(CeilingFan* cf) {
		ceilingFan = cf;
	}
	void execute() {
		prevSpeed = ceilingFan->getSpeed();
		ceilingFan->high();
	}
	void 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();
		}
	}
};

class CeilingFanLowCommand :public Command {
private:
	CeilingFan* ceilingFan;
	int prevSpeed;
public:
	CeilingFanLowCommand(CeilingFan* cf) {
		ceilingFan = cf;
	}
	void execute() {
		prevSpeed = ceilingFan->getSpeed();
		ceilingFan->low();
	}
	void 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();
		}
	}
};

class CeilingFanMediumCommand :public Command {
private:
	CeilingFan* ceilingFan;
	int prevSpeed;
public:
	CeilingFanMediumCommand(CeilingFan* cf) {
		ceilingFan = cf;
	}
	void execute() {
		prevSpeed = ceilingFan->getSpeed();
		ceilingFan->medium();
	}
	void 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();
		}
	}
};

class CeilingFanOffCommand :public Command {
private:
	CeilingFan* ceilingFan;
	int prevSpeed;
public:
	CeilingFanOffCommand(CeilingFan* cf) {
		ceilingFan = cf;
	}
	void execute() {
		prevSpeed = ceilingFan->getSpeed();
		ceilingFan->off();
	}
	void 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();
		}
	}
};

class GarageDoorUpCommand :public Command {
private:
	GarageDoor* garageDoor;
public:
	GarageDoorUpCommand(GarageDoor* gd) {
		garageDoor = gd;
	}
	void execute() {
		garageDoor->up();
	}
	void undo() {
		garageDoor->down();
	}
};

class GarageDoorDownCommand :public Command {
private:
	GarageDoor* garageDoor;
public:
	GarageDoorDownCommand(GarageDoor* gd) {
		garageDoor = gd;
	}
	void execute() {
		garageDoor->down();
	}
	void undo() {
		garageDoor->up();
	}
};


class StereoOnWithCDCommand :public Command {
private:
	Stereo* stereo;
public:
	StereoOnWithCDCommand(Stereo* ster) {
		stereo = ster;
	}
	void execute() {
		stereo->on();
		stereo->setCD();
		stereo->setVolume(11);
	}
	void undo() {
		stereo->off();
	}
};

class StereoOffCommand :public Command {
private:
	Stereo* stereo;
public:
	StereoOffCommand(Stereo* ster) {
		stereo = ster;
	}
	void execute() {
		stereo->off();
	}
	void undo() {
		stereo->on();
		stereo->setCD();
		stereo->setVolume(11);
	}
};

使用NoCommand对象,以便确定每个slot永远都有命令对象

class NoCommand :public Command {
public:
	void execute() {
		printf("No Command\n");
	}
	void undo() {
		printf("No Command\n");
	}
};

定义宏命令

class MacroCommand :public Command {
private:
	Command** commands;
	int commands_count;
public:
	MacroCommand(Command** com, int commandsNo) {
		commands = com;
		commands_count = commandsNo;
	}

	void execute() {
		for (int i = 0; i < commands_count; i++) {
			commands[i]->execute();
		}
	}

	void undo() {
		for (int i = 0; i < commands_count; i++) {
			commands[i]->undo();
		}
	}
};

实现命令模式的客户

class RemotrControl {
private:
	Command** onCommands;
	Command** offCommands;
	std::vector<Command*> undoCommand;

public:
	RemotrControl() {
		onCommands = new Command*[7];
		offCommands = new Command*[7];

		Command* noCommand = new NoCommand();
		for (int i = 0; i < 7; i++)	{
			onCommands[i] = noCommand;
			offCommands[i] = noCommand;
		}
		undoCommand.push_back(noCommand);
	}

	void setCommand(int slot, Command* onCommand, Command* offCommand) {
		onCommands[slot] = onCommand;
		offCommands[slot] = offCommand;
	}

	void onButtonWasPushed(int slot) {
		onCommands[slot]->execute();
		undoCommand.push_back(onCommands[slot]);
	}

	void offButtonWasPushed(int slot) {
		offCommands[slot]->execute();
		undoCommand.push_back(offCommands[slot]);
	}

	void undoButtonWasPushed() {
		if (undoCommand.empty()){
			printf("No Command\n");
		}
		else {
			undoCommand.back()->undo();
			undoCommand.pop_back();
		}
	}
};

测试

void main() {
	RemotrControl* remotrControl = new RemotrControl();

	Light* livingRoomLight = new Light("Living Room");
	Light* kitchenLight = new Light("Kitchen");
	CeilingFan* ceilingFan = new CeilingFan("Living Room");
	GarageDoor* garageDoor = new GarageDoor("");
	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);

	GarageDoorUpCommand* garageDoorUp = new GarageDoorUpCommand(garageDoor);
	GarageDoorDownCommand* garageDoorDown = new GarageDoorDownCommand(garageDoor);

	StereoOnWithCDCommand* StereoOnWithCD = new StereoOnWithCDCommand(stereo);
	StereoOffCommand* StereoOff = new StereoOffCommand(stereo);

	remotrControl->setCommand(0, livingRoomLightOn, livingRoomLightOff);
	remotrControl->setCommand(1, kitchenLightOn, kitchenLightOff);
	remotrControl->setCommand(3, StereoOnWithCD, StereoOff);
	remotrControl->setCommand(4, garageDoorUp, garageDoorDown);
	
	for (int i = 0; i < 7; i++)	{
		remotrControl->onButtonWasPushed(i);
		remotrControl->offButtonWasPushed(i);
	}
	printf("undo test------------------------------------------------------\n");
	remotrControl->offButtonWasPushed(0);
	remotrControl->undoButtonWasPushed();
	remotrControl->offButtonWasPushed(0);
	remotrControl->onButtonWasPushed(0);
	remotrControl->undoButtonWasPushed();
	remotrControl->undoButtonWasPushed();
	remotrControl->undoButtonWasPushed();
	printf("------------------------------------------------------\n");
	CeilingFanMediumCommand* ceilingFanMedium = new CeilingFanMediumCommand(ceilingFan);
	CeilingFanHighCommand* ceilingFanHigh = new CeilingFanHighCommand(ceilingFan);
	CeilingFanOffCommand* ceilingFanOff = new CeilingFanOffCommand(ceilingFan);
	remotrControl->setCommand(0, ceilingFanMedium, ceilingFanOff);
	remotrControl->setCommand(1, ceilingFanHigh, ceilingFanOff);
	remotrControl->onButtonWasPushed(0);
	remotrControl->offButtonWasPushed(0);
	remotrControl->undoButtonWasPushed();
	remotrControl->onButtonWasPushed(1);
	remotrControl->undoButtonWasPushed();
	remotrControl->undoButtonWasPushed();
	remotrControl->undoButtonWasPushed();
	printf("MacroCommand test------------------------------------------------------\n");
	Command* partyOn[] = { livingRoomLightOn,kitchenLightOn,StereoOnWithCD,garageDoorUp };
	Command* partyOff[] = { livingRoomLightOff,kitchenLightOff,StereoOff,garageDoorDown };
	MacroCommand* partyOnMacro = new MacroCommand(partyOn, 4);
	MacroCommand* partyOffMacro = new MacroCommand(partyOff, 4);
	remotrControl->setCommand(0, partyOnMacro, partyOffMacro);
	remotrControl->onButtonWasPushed(0);
	remotrControl->offButtonWasPushed(0);
	remotrControl->undoButtonWasPushed();
	remotrControl->undoButtonWasPushed();

}

参考:

1. EricFreeman, FreemanElisabeth, 弗里曼, et al. Head First设计模式[M]. 中国电力出版社, 2007.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值