命令模式(Command)

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

简单来讲,命令模式可以将不同的请求封装成统一的访问方式,比如有些请求函数名是 request1()、有些请求函数名是 request2(),我们通过命令方式可以将其请求函数名统一改成 request,这样便于将多个不同的请求放在同一个容器中,统一遍历访问请求队列即可。

首先,我们先定义命令的接口类,该类用于声明用于同一执行的命令接口叫什么名字,接口类不做任何具体的操作实现。

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

接下来,我们定义一个类,该类封装了多个不同的操作。如下 Receiver 类定义了四种针对该对象的运算操作。

class Receiver
{
public:
	
	void add(int num)
	{
		this->m_number += num;
	}

	void minus(int num)
	{
		this->m_number -= num;
	}
	
	void multiply(int num)
	{
		this->m_number *= num;
	}

	void divide(int num)
	{
		this->m_number /= num;
	}

public:
	int m_number {0};
};

我们知道用户可能会针对该对象执行多个不同的操作,为了能够将这些操作封装到同一个容器中,我们可以实现多个具体的命令类,该类需要继承 Command 接口类,如下代码所示:

class AddCommand : public Command
{
public:

	AddCommand(Receiver *receiver) : p_receiver(receiver){}

	virtual void excute()
	{
		p_receiver->add(100);
	}

	virtual void undo()
	{
		p_receiver->minus(100);
	}
private:
	Receiver *p_receiver;

};

class MinusCommand : public Command
{
public:

	MinusCommand(Receiver* receiver) : p_receiver(receiver) {}

	virtual void excute()
	{
		p_receiver->minus(20);
	}

	virtual void undo()
	{
		p_receiver->add(20);
	}
private:
	Receiver* p_receiver;
};


class MultiplyCommand : public Command
{
public:
	MultiplyCommand(Receiver* receiver) : p_receiver(receiver) {}

	virtual void excute()
	{
		p_receiver->multiply(3);
	}

	virtual void undo()
	{
		p_receiver->divide(3);
	}
private:
	Receiver* p_receiver;
};


class DivideCommand : public Command
{
public:
	DivideCommand(Receiver* receiver) : p_receiver(receiver) {}

	virtual void excute()
	{
		p_receiver->divide(2);
	}

	virtual void undo()
	{
		p_receiver->multiply(2);
	}
private:
	Receiver* p_receiver;
};

此刻,用户针对 receiver 对象进行了加减乘除四种操作,我们实例化 4 种操作命令,并将其存储到 vector 容器中,方便简单撤消操作的实现。

#include <iostream>
#include <vector>

int main()
{
	// 操作对象
	Receiver receiver;
	// 操作命令
	Command *comman1 = new AddCommand(&receiver);
	Command *comman2 = new MinusCommand(&receiver);
	Command *comman3 = new MultiplyCommand(&receiver);
	Command *comman4 = new DivideCommand(&receiver);

	// 存储请求
	std::vector<Command*> command_list;
	command_list.push_back(comman1);
	command_list.push_back(comman2);
	command_list.push_back(comman3);
	command_list.push_back(comman4);

	// 执行操作
	for (Command *command : command_list)
	{
		command->excute();
	}
	std::cout << receiver.m_number << std::endl;  // 120

	// 撤销操作
	for (auto it = command_list.rbegin(); it != command_list.rend(); ++it)
	{
		(*it)->undo();
	}

	std::cout << receiver.m_number << std::endl;  // 0

	return 0;
}

从上面的实现过程,我们可以看到命令模式中就是将不同操作接口、或者不同的请求进行封装以使得执行接口统一,便于统一的执行。假设只为了实现该功能,我们也可以在设计类时,将 Receiver 类重新设计也可以实现。

如果不知道是否用设计模式,那就不要用,它带来便利的同时,也会使得代码实现变得复杂。

未经允许不得转载:一亩三分地 » 命令模式(Command)