1. 程式人生 > >模式六:命令模式(Command Pattern)——封裝請求物件

模式六:命令模式(Command Pattern)——封裝請求物件

命令模式

將“請求”封裝成物件,以便使用不同的請求、佇列或者日誌來引數化其他物件。命令模式也支援可撤銷的操作。

應用分析

命令模式的設計,定義公共的Command介面,使請求呼叫者和請求接收者之間解耦,便於請求擴充套件。

Command:定義命令的統一介面
ConcreteCommand:Command介面的實現者,用來執行具體的命令,某些情況下可以直接用來充當Receiver。
Receiver:命令的實際執行者
Invoker:命令的請求者,是命令模式中最重要的角色。這個角色用來對各個命令進行控制。

例項分析

用一個遙控器控制不同電器,執行不同操作,比如:燈的開關、電視機的開關等,這樣,我們可以將最終的接收者燈和電視的行為封裝成命令物件,通過命令物件的統一介面execute執行相關操作。

程式碼分析

//Command.h
//Command介面
#ifndef COMMAND_H
#define COMMAND_H

#include <iostream>

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

class NoCommand:public Command
{
public:
	void execute()
	{
		std::cout<<"Nothing on"<<std::endl;
	}
	void undo()
	{
		std::cout<<"Nothing off"<<std::endl;
	}
};
#endif


//Receiver.h
//接收者
#ifndef RECEIVER_H
#define RECEIVER_H

#include <iostream>

class Light
{
public:
	void on()
	{
		std::cout<<"Light on"<<std::endl;
	}
	void off()
	{
		std::cout<<"Light off"<<std::endl;
	}
};

class TV
{
public:
	void on()
	{
		std::cout<<"TV on"<<std::endl;
	}
	void off()
	{
		std::cout<<"TV off"<<std::endl;
	}
};

#endif


//ConcreteCommand.h
//命令實體物件
#ifndef COMCRETECOMMAND_H
#define COMCRETECOMMAND_H

#include "Command.h"
#include "Receiver.h"

class OnTVCommand:public Command
{
private:
	TV &TVReceive;
public:
	OnTVCommand(TV & TVre):TVReceive(TVre){}
	void execute()
	{
		TVReceive.on();
	}
	void undo()
	{
		TVReceive.off();
	}
};

class OffTVCommand:public Command
{
private:
	TV &TVReceive;
public:
	OffTVCommand(TV & TVre):TVReceive(TVre){}
	void execute()
	{
		TVReceive.off();
	}
	void undo()
	{
		TVReceive.on();
	}
};

class OnLightCommand:public Command
{
private:
	Light &LightReceiver;
public:
	OnLightCommand(Light &LightRe):LightReceiver(LightRe){}
	void execute()
	{
		LightReceiver.on();
	}
	void undo()
	{
		LightReceiver.off();
	}
};

class OffLightCommand:public Command
{
private:
	Light &LightReceiver;
public:
	OffLightCommand(Light &LightRe):LightReceiver(LightRe){}
	void execute()
	{
		LightReceiver.off();
	}
	void undo()
	{
		LightReceiver.on();
	}
};

#endif


//Invoker.h
//呼叫者
#ifndef INVOKER_H
#define INVOKER_H

#include "Command.h"

class Command;
NoCommand noCommand;

class Invoker
{
private:
	Command * undoCommand;
	Command * onCommands[7];
	Command * offCommands[7];
public:
	Invoker()
	{
		for(int i=0;i<7;++i)
		{
			onCommands[i]=&noCommand;
			offCommands[i]=&noCommand;
		}
		undoCommand=&noCommand;
	}
	void setCommand(int slot,Command & onCommand,Command & offCommand)
	{
		onCommands[slot]=&onCommand;
		offCommands[slot]=&offCommand;
	}
	void onButton(int slot)
	{
		onCommands[slot]->execute();
		undoCommand=onCommands[slot];
	}
	void offButton(int slot)
	{
		offCommands[slot]->execute();
		undoCommand=offCommands[slot];
	}
	void undo()
	{
		undoCommand->undo();
	}
};

#endif

//Main.cpp
//測試程式
#include "ConcreteCommand.h"
#include "Invoker.h"

int main()
{
	TV tv;
	Light light;

	OnTVCommand ontvCommand(tv);
	OffTVCommand offtvCommand(tv);
	OnLightCommand onlightCommand(light);
	OffLightCommand offlightCommand(light);

	Invoker invoker;
	invoker.setCommand(0,ontvCommand,offtvCommand);
	invoker.setCommand(1,onlightCommand,offlightCommand);

	invoker.onButton(0);
	invoker.offButton(1);
	invoker.onButton(3);
	invoker.onButton(1);
	invoker.undo();
	return 0;
}