首页 > 搜索 > 设计模式基于C,C常用设计模式——命令模式

设计模式基于C,C常用设计模式——命令模式

互联网 2021-01-27 17:36:30
在线算命,八字测算命理

写在开头:这个系列不是给C语言硬套设计模式,而是讨论在这些场景下,C语言最合适的实现方式,灵活运用指针和设计模式是良好设计的基础。当然我也会说一些硬套设计模式怎么写,请大家注意文章里的前后分界。

命令(Command)模式,从字面理解,就是客户有个命令,服务响应这个命令。每次我们都要从字面开始去理解一个模式,因为名字最能反映一个模式的目标、核心和应用场景。

(这个模式的核心在于把命令下达与命令执行在时间上进行分离,如果没有这个核心,C语言里的命令模式将与状态模式没有区别。)

宋江命令李逵做事,这回李逵没有选择的余地了,不能根据自己的当前状态来选择下一步要做的事了,宋江命令什么他得做什么。宋江命令吃饭就吃饭,命令战斗就战斗,命令休息就休息。这个需求让林冲做,命令模式看重的是命令客户端与命令执行体之间的关系,我们要求林冲把客户端程序也写出来。

//提供给客户端程序的接口void LikuiAction(int songjiangCmd);//用例程序_客户端程序test(test_SongjiangCmd_LikuiRespond){int songjiangCmd = EAT;LikuiAction(SongjiangCmd);//忽略用例校验}//命令响应程序void LikuiAction(int songjiangCmd){switch(songjiangCmd){case EAT:Eat();break;case FIGHT:Fight();break;case REST:Rest();break;default:DoNothing();}}

代码交给卢俊义评审,老卢一看,“这个代码写得中规中矩。但是这个代码架构绑死了命令下达与命令执行的时间关系,不够灵活呀”。

又来一个需求:李逵收到吴用军师的命令也必须听,李逵又没办法不听谁的命令,那就谁先来执行谁好了。这个需求再交给林冲实现。

林冲一看傻眼了,这需求竟然真的加入了先后的时间因素,这个因素在架构设计的一开始就没考虑,趁着代码还没写太多,赶紧推翻重写吧。林冲代码如下:

//提供给客户端程序的接口typedef struct Cmd{int cmdNum;int cmd[100]}Cmd;void DoCmd(Cmd *cmd);//用例程序_客户端程序test(test_SongjiangCmd_LikuiRespond){Cmd cmd;cmd.cmd[0] = EAT;cmd.cmd[1] = FIGHT;cmd.cmdNum = 2;DoCmd(&cmd);//忽略用例校验}//命令响应程序void DoCmd(Cmd *cmd){for(int i = 0; i cmdNum; i++){LikuiAction(cmd->cmd[i]);}}void LikuiAction(int leaderCmd){switch(leaderCmd){case EAT:Eat();break;case FIGHT:Fight();break;case REST:Rest();break;default:DoNothing();}}

代码交给老卢评审,老卢道:“早这样做多好。这便是命令模式的简单版了。从这简单版里,仔细体会一下,命令模式之核心并不是灵活多变的函数/对象关系,其核心在于剥离命令下达和命令执行的时间关系,并且通过一个数据结构进行中转引入一个中间层,给下达和执行各自的变化方向留了扩展可能。”林冲深以为然。

也许有人会说,哪里剥离时间关系了,还不是一样cmd赋值完之后调用DoCmd吗?这只是一个模拟,实际中,你可以把这个结构存到DDR或者文件,客户端和响应端可以是不同的进程,在进程运行起来去对应位置读取数据即可。上面的demo只是用来表意。

老卢又问:“代码还能怎么改进吗?”

林冲想了想,道:“LikuiAction那个switch可以改成表驱动。”

老卢道:“嗯,能优化就优化嘛。你写写看?”。林冲修改switch代码如下:

typedef void (*likuiAction)();likuiAction flikuiAction[3] = {Eat, Fight, Rest};//命令响应程序void DoCmd(Cmd *cmd){for(int i = 0; i cmdNum; i++){flikuiAction[cmd->cmd[i]]();}}

老卢看了看,说:”这个例子很简单了,如果每个处理函数如Eat的入参不同,你可能就需要维护一个新的结构,结构里存储处理函数和函数入参,这属于函数指针的灵活运用,跟命令模式没什么关系。“

老卢停顿了一下,接着说,“大多数软件是下面这个结构,

“这是命令模式的典型结构,这个结构跟上面的demo是不一样的。哪里不一样看出来了吗?”

林冲想了想,“demo没有区分配置响应程序和运行程序”。

老卢:“不错。这个结构意味着,我们可以在配置响应程序里做更多的事情,来降低运行程序的开销和复杂度。怎么理解这句话呢?命令也许来自多个梁山头目,响应程序需要根据不同头目的不同命令类型做出不同的判断,比如当吴用和宋江在同一条命令下达的时候,要听宋江的。我们可以把复杂的条件判断放在配置响应程序里,给运行程序一个非常简单的命令响应结果。”

命令模式通过增加中转数据结构,使命令下达和命令执行二者依赖于接口,从而达到二者时间上不相关、二者变化方向独立的目的。

参考书目:《软件架构与模式》

参考链接:https://blog.csdn.net/wqx521/article/details/93589663 这篇文章写得不错,但仔细看代码,你会发现这篇文章描述的只是函数指针的灵活应用,同样的代码你可以套在状态模式上,缺少了命令模式应用的核心。可能是因为例子不合适,作者没有强调重点。作为大家的扩展例子阅读还是不错的。

免责声明:非本网注明原创的信息,皆为程序自动获取互联网,目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责;如此页面有侵犯到您的权益,请给站长发送邮件,并提供相关证明(版权证明、身份证正反面、侵权链接),站长将在收到邮件12小时内删除。

相关阅读