设计模式(19)-命令模式

Posted by Tango on March 13, 2016

在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”,但在某些实际应用场景下我们需要对请求进行记录、撤销等操作,这是这种紧耦合的结构不能满足需求的变化,此时我们可以使用命令(Command)模式来应用在这种场景。

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。

1.模式适用性

  • 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
  • 系统需要在不同的时间指定请求、将请求排队和执行请求。
  • 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
  • 系统需要将一组操作组合在一起,即支持宏命令。

2.模式结构

(1)Command: 执行命令的接口。

(2)ConcreteCommand: 实现Command的具体类,将一个接收者(Receiver)对象绑定于一个动作,调用接收者相应的操作,以实现Execute。

(3)Invoker: 命令的管理者,具体的撤销,重做,记录等功能都在这里实现。

(4)Receiver: 知道如何实施与执行一个相关的操作,即操作最终的实现者。

3.实现

#include <iostream>

class Receiver
{
public:
        void Action()
        {
                std::cout << "Action..." << std::endl;
        }
};

class Command
{
protected:
	Receiver *receiver;
public:
	Command(Receiver *r)
	{
		this->receiver = r;
	}
	virtual ~Command(){}
	virtual void Execute() = 0;
};

class ConcreteCommand : public Command
{
public:
	ConcreteCommand(Receiver *r) : Command(r) {}
	~ConcreteCommand() {}
	void Execute() 
	{
		receiver->Action();
	}
};

class Invoker
{
private:
	Command *command;
public:
	void SetCommand(Command *c)
	{
		this->command = c;
	}

	void ExecuteCommand()
	{
		command->Execute();
	}
};


int main()
{
	Receiver *r = new Receiver();
	Command *c = new ConcreteCommand(r);
	Invoker *i = new Invoker();

	i->SetCommand(c);
	i->ExecuteCommand();

	delete r;
	delete c;
	delete i;
}

4.总结

命令模式可以比较容易的实现一个命令队列,并且对这个命令队列进行管理,支持撤销和重做等功能。而且对于“行为请求者”和“行为实现着”进行了很好的分离。使用整个模式修改点在ConcreteCommand和Invoker,所以我们可以不比修改客户端代码而进行扩展和功能修改。