设计模式之命令模式

命令模式将请求封装成对象,以便使用不同的请求、队列或者日志来参数化其它对象。命令模式也支持可撤销的操作。通过定义一个统一的抽象Command类,这个类声明了两个纯虚函数(如果要加入日志等功能也可以再追加),一个是请求命令函数execute(),另一个是撤销命令函数undo(),然后所有的具体命令都继承自这个Command类,具体命令中包含了实现具体动作的对象(receiver)的引用或指针,具体命令需要重写execute()函数,在里面加入receiver的具体动作,同时在重写的undo里面加入receiver对应的撤销动作。这样客户类只需要保留一个指向Command对象的引用或指针,然后通过调用Comand的两个函数,就能实现相应的动作,而不用关心具体命令的实现以及命令动作的实现对象,即实现了动作请求和执行对象的解耦。

命令模式的类图如下:


下面通过设计一个遥控器的具体实例,来说明命令模式的使用:该遥控器实现了电灯、音响的开关命令和各自的撤销,具体程序如下:

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <memory>
#include <string>
using namespace std;
//命令接收者(类图中的receiver)
class Light {
public :
	Light(string location) 
	{
		this->location = location;
	}
	void on() 
	{
		cout<<location<<" light is on"<<endl;
	}
	void off() 
	{
		cout<<location<<" light is off"<<endl;
	}
private:
	string location;
};
//命令接收者(类图中的receiver)
class Stereo {
private:
	string location;

public:
	Stereo(string location) {
		this->location = location;
	}
	void on() {
		cout<<location<<" stereo is on"<<endl;
	}

	void off() {
		cout<<location <<" stereo is off"<<endl;
	}

	void setCD() {
		cout<<location <<" stereo is set for CD input"<<endl;
	}
	void setVolume(int volume) {
		cout<<location <<" Stereo volume set to "<<volume<<endl;
	}
};
//抽象命令接口类
class Command {
public: 
	virtual void execute()=0;
	virtual void undo()=0;
};
//默认命令对象
class NoCommand :public Command {
public :
	void execute() 
	{ 
		cout<<"There is not a valid command"<<endl;
	}
	void undo()
	{
		cout<<"There is not a valid command"<<endl;
	}
};
//具体命令对象
class LightOnCommand :public Command {
private:
	shared_ptr<Light> light;
public:
	LightOnCommand(shared_ptr<Light>light) {
		this->light = light;
	}
	void execute() 
	{
		light->on();
	}
	void undo()
	{
		light->off();
	}
};
//具体命令对象
class LightOffCommand  :public Command {
private:
	shared_ptr<Light> light;
public:
	LightOffCommand (shared_ptr<Light> light) {
		this->light = light;
	}
	void execute() //请求动作
	{
		light->off();
	}
	void undo()  //撤销动作
	{
		light->on();
	}
};
//具体命令对象
class StereoOnWithCDCommand:public Command {
private:
	shared_ptr<Stereo> stereo;
public:
	StereoOnWithCDCommand(shared_ptr<Stereo> stereo) {
		this->stereo = stereo;
	}
	void execute() {
		stereo->on();
		stereo->setCD();
		stereo->setVolume(11);
	}
	void undo()
	{
		stereo->off();
	}
};
//具体命令对象
class StereoOffCommand :public Command {
private:
	shared_ptr<Stereo> stereo;
public:
	StereoOffCommand (shared_ptr<Stereo> stereo) {
		this->stereo = stereo;
	}
	void execute() {
		stereo->off();
	}
	void undo()
	{
		stereo->on();
		stereo->setCD();
		stereo->setVolume(11);
	}
};
//客户(即类图中client)
class RemoteControl {
private:
	vector<shared_ptr<Command>> onCommands;  //实现多个开命令(命令对象指针或引用)
	vector<shared_ptr<Command>> offCommands;  //实现多个关命令(命令对象指针或引用)
public:
	RemoteControl() {
		onCommands=vector<shared_ptr<Command>>(2,nullptr);
		offCommands =vector<shared_ptr<Command>>(2,nullptr);
		//给命令对象赋默认值
		shared_ptr<Command> noCommand=shared_ptr<Command>(new NoCommand);
		for (int i = 0; i < 2; i++) {
			onCommands[i] = noCommand;
			offCommands[i] = noCommand;
		}
	}
	//设置命令对象
	void setCommand(int slot, shared_ptr<Command> onCommand, shared_ptr<Command> offCommand) {
		onCommands[slot] = onCommand;
		offCommands[slot] = offCommand;
	}
	void onButtonWasPushed(int slot) {
		onCommands[slot]->execute();
	}
	void offButtonWasPushed(int slot) {
		offCommands[slot]->execute();
	}
	void undoButtonWasPushed(int slot)
	{
		offCommands[slot]->undo();
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	RemoteControl remoteControl ;
	shared_ptr<Light> kitchenLight=shared_ptr<Light>(new Light("Kitchen"));
	shared_ptr<LightOnCommand> kitchenLightOn =
		shared_ptr<LightOnCommand>(new LightOnCommand(kitchenLight));
	shared_ptr<LightOffCommand> kitchenLightOff = 
		shared_ptr<LightOffCommand>(new LightOffCommand(kitchenLight));
	shared_ptr<Stereo> stereo=shared_ptr<Stereo>(new Stereo("Living Room"));
	shared_ptr<StereoOnWithCDCommand> stereoOnWithCD =
		shared_ptr<StereoOnWithCDCommand>(new StereoOnWithCDCommand(stereo));
	shared_ptr<StereoOffCommand> stereoOff =
		shared_ptr<StereoOffCommand>(new StereoOffCommand(stereo));
	remoteControl.setCommand(0, kitchenLightOn, kitchenLightOff);
	remoteControl.setCommand(1, stereoOnWithCD, stereoOff);
	remoteControl.onButtonWasPushed(0);
	remoteControl.offButtonWasPushed(0);
	remoteControl.undoButtonWasPushed(0);
	remoteControl.onButtonWasPushed(1);
	remoteControl.offButtonWasPushed(1);
	remoteControl.undoButtonWasPushed(1);
	return 0;
}
程序执行结果如下:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值