命令模式
命令模式是一种行为模式,用于将请求或频繁调用关系管理起来,封装成对象行为。
意义
在平常的设计中,对于不同模块之间调用关系,通常通过头文件直接调用接口即可。随着需求的增多,调用越来越多。最终维护起来会发现如下问题:
- 代码裁剪时任务量大。由于调用过多,且调用关系散落各处,导致裁剪代码时,不敢轻易下手。
- 各个组件关系复杂。在实际的编程中,经常会遇到一些“特殊”场景,需要特殊处理(组件之间调用),而这些代码又未规范起来。因此在新人维护代码时,会忽略这些特殊场景。更恐怖的是,遇到重复的需求,又加上重复的代码。
- 代码变得“不纯粹”。
命令模式可以解决以上问题。
类图
命令模式Invoker:
执行实例,此对象完成命令申请和命令响应的整个流程。
Command:
命令对象基类,定义命令类的模板。
LedCmd、MotorCmd:
具体的命令类,其内部会持有Receiver的指针,用于将具体的命令实例和响应实例绑定。此类中,可以做一些对命令的管理等操作。
Receiver:
命令响应类,用于响应某个命令的执行动作。
Client:
客户端代码,如果规范起来的话,Client应只能访问对外释放的接口。在此指定命令与指定响应行为绑定。
总结
- 命令模式将模块之间的调用关系,分离为命令发起、命令处理和命令响应,从而完成代码间的解耦。
- 命令对象与响应对象通过动态的注册的方式来实现,更容易完成响应者的替换。
- 加入新的需求时,只需要增加新的对象即可,无需修改原先的业务代码,更加安全。
- 但是此种命令模式,客户端要创建和销毁很多实例,这对于使用者来说是麻烦的操作。优化代码已经完成,等后续总结一篇来介绍。可公众号获取优化的代码。
源码
#include <iostream>
#include <string>
using namespace std;
// 命令响应
class Receiver
{
public:
explicit Receiver(string operation)
{
mOperation = operation;
}
void Action()
{
cout << mOperation << endl;
}
private:
string mOperation;
};
class Command
{
public:
virtual ~Command()
{
}
virtual void Execute() = 0;
protected:
Command()
{
}
};
class LedCmd : public Command
{
public:
void Execute()
{
if (NULL != mRcv) {
this->mRcv->Action();
}
}
explicit LedCmd(Receiver *pRcv)
{
if (NULL != pRcv) {
mRcv = pRcv;
}
else
{
mRcv = NULL;
cout << "Error: Param failed!" << endl;
}
}
private:
Receiver *mRcv;
};
class MotorCmd : public Command
{
public:
void Execute()
{
if (NULL != mRcv) {
this->mRcv->Action();
}
}
explicit MotorCmd(Receiver *pRcv)
{
if (NULL != pRcv) {
mRcv = pRcv;
}
else
{
mRcv = NULL;
cout << "Error: Param failed!" << endl;
}
}
private:
Receiver *mRcv;
};
class Invoker
{
public:
explicit Invoker(Command *pCmd)
{
if (NULL != pCmd)
{
mCmd = pCmd;
}
else
{
mCmd = NULL;
cout << "Error: Param failed!" << endl;
}
}
// 所有的命令响应动作都会经此接口触发, 可以在此处实现对命令的管理设计
void Invoke()
{
if (NULL != mCmd) {
mCmd->Execute();
}
else {
cout << "Error: no action" << endl;
}
}
private:
Command *mCmd;
};
int main(int argc, char *argv[])
{
Receiver *theLedRcv = new Receiver("Led");
LedCmd *theLedCmd = new LedCmd(theLedRcv);
Invoker *theLedManager = new Invoker(theLedCmd);
theLedManager->Invoke();
Receiver *theMotorRcv = new Receiver("Motor");
LedCmd *theMotorCmd = new LedCmd(theMotorRcv);
Invoker *theMotorManager = new Invoker(theMotorCmd);
theMotorManager->Invoke();
delete theLedRcv;
delete theLedCmd;
delete theLedManager;
delete theMotorRcv;
delete theMotorCmd;
delete theMotorManager;
return 0;
}
$ ./a.out
Led
Motor
网友评论