命令模式用于将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
简单来讲,命令模式可以将不同的请求封装成统一的访问方式,比如有些请求函数名是 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 类重新设计也可以实现。
如果不知道是否用设计模式,那就不要用,它带来便利的同时,也会使得代码实现变得复杂。

冀公网安备13050302001966号