C++实现命令模式

1. 情景与意图

  如果学习过Linux操作系统的同学会知道,使用Linux操作系统的同学一般是不会用鼠标点来点去,虽然是带有桌面的,我们通常是使用命令的方式。说到这,无耻的引流来了,如果有对Linux操作系统感兴趣的话,欢迎关注【Linux操作系统学习系列】
  话说回来,如果说上面的流程用下面的代码来实现:

// 伪代码
void lsFunc(){}
void cdFunc(){}
void pwdFunc(){}
void command(int cmd) {
	switch(cmd)
	case 1: lsFunc()
		break;
	case 2: cdFunc()
		break;
	case 3: pwdFunc()
		break;
}

此时就会有问题,我们新增 grep 、top、netstat等命令,就要修改 command()这个方法了,会导致command这个方法越来越臃肿。这里面的问题就是调用和实现紧耦合,在某些场景下,我们应该将调用和实现解耦,怎么实现这种设计呢?——命令模式

2. 命令模式

  将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。
  在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
  怎么解释其实都不好理解,下面我们就用命令模式来实现这个shell,通过代码学习命令模式。

3. Shell

  先定义我们的shell命令。这个shell的设计其实也不好,更好的是,我们继续将shell进行抽象,这样在后面新增命令的时候不用再更改这个类,方便扩展,但是这里不这样实现,为了更方便的阅读与演示。

class DPShell {
public:
	void ls(std::string arg);
	void cd(std::string arg);
	void pwd();
};

  然后建立一个中间调用类。主要是为了将上面的shell类的每一个方法进行隔离,为的是将第一节演示的switch的判断语句进行拆解,这样就不用在一个方法里面进行调用。

class DPCommand {
protected:
	string _info;
public:
	virtual string info() = 0;
	virtual void execute() = 0;
};
class DPLsCommad :public DPCommand {
	// 这个shell其实可以抽离到父类
	DPShell _shell;
	std::string _arg;
public:
	DPLsCommad(std::string arg = "");
	virtual string info();
	virtual void execute();
};

class DPCdCommad :public DPCommand {
	/* 省略	*/
};

class DPPwdCommad :public DPCommand {
	/* 省略	*/
};

实现其中一个吧,其余都是一样的

DPLsCommad::DPLsCommad(std::string arg)
	:_arg(arg) {
	_info = string("ls") += arg;
}
string DPLsCommad::info() {
	return _info;
}
void DPLsCommad::execute() {
	_shell.ls(_arg);

然后我们实现一个核心调用类。主要是管理我们命令的调用

class DPInvoker {
	vector<DPCommand*> _comList;

public:
	void execute(DPCommand* cmd);
	void showHistoryCommand();
	void executeCmdWithIndex(size_t index);
};

void DPInvoker::execute(DPCommand* cmd) {
	if (cmd != nullptr) {
		cmd->execute();
		_comList.push_back(cmd);
	}
}

void DPInvoker::showHistoryCommand() {
	for (auto cmd : _comList) {
		std::cout << cmd->info() << std::endl;
	}
}
void DPInvoker::executeCmdWithIndex(size_t index) {
	if (index < _comList.size()) {
		execute(_comList[index]);
	}
}

看一下mian 函数吧。可以看到shell其实已经被隐藏了,我们也没有一个臃肿的switch。这就是命令模式的好处。

int main() {
	DPCommand* lsCmd = new DPLsCommad();
	DPInvoker invoker;
	invoker.execute(lsCmd);
	invoker.showHistoryCommand();
	return 0;
}

4. 总结

  再看看概念:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。请求就是说我们将对象的行为封装成命令,比如shell对象的ls方法,封装成DPLsCommad对象。最简单的理解就是把这个命令对象当成一个函数指针,好处就是更加的灵活。
  命令模式将调用与实现进行了松耦合,降低了系统耦合度,新的命令也可以很容易添加到系统中去。缺点也很明显,使用命令模式可能会导致某些系统有过多的具体命令类。
博文省略了一些代码,详细代码见C++实现命令模式代码:【命令模式C++源码】

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值