c语言设计模式代码完整实现-命令模式(command)

c语⾔设计模式代码完整实现-命令模式(command)
模式介绍:命令模式(command)
命令模式的解释如下:
向对象发送⼀个请求,但是并不知道该请求的具体接收者是谁,具体的处理过程是如何的,只知道在程序运⾏中指定具体的请求接收者即可,对于这样将请求封装成对象的我们称之为命令模式。所以命令模式将请求封装成对象,以便使⽤不同的请求、队列或者⽇志来参数化其他对象。同时命令模式⽀ 持可撤销的操作。
命令模式的C语⾔实现也是⾮常显性的。命令发送⽅不通过直接调⽤的⽅式,⽽是通过发⼀个命令消息给接收⽅,让接收⽅执⾏操作。C语⾔⾥采⽤命令模式的最常见的原因是核间通信,进程间交互。如果是核间通信,通常是把命令按协定的格式封装在消息数据包⾥。如果是进程间通信,通常封装成⼀个结构体,把参数带过去。命令的通道通常是队列。
命令模式实现
实现流程
C语⾔命令模式经典⽅式如下,和⾯向对象是有明显的不同的。下图的invoker表⽰发命令的实体,⽽handler表⽰执⾏命令的实体,这个和⾯向对象的命令模式⾥的含义不⼀样。
图表 1 C语⾔命令模式⽰意图
图表 2⾯向对象命令模式
C语⾔实现的命令模式核⼼数据结构是命令。发布命令的是invoker,多个invoker将命令封装起来,送到队列⾥。有⼀个函数或者线程称为receiver,检查队列⾥是否有没有处理的命令。由receiver负责调⽤各个handler。另外⼀个被经常使⽤的辅助数据结构是命令码数组,在如果invoker和handler运⾏于不同的环境,这种做法⼏乎是必选,如核间通信,内核和应⽤态通信。命令码作为索引,handler调⽤函数作为元素,Receiver根据不同的命令码调⽤handler。
也有不使⽤消息队列的C语⾔实现。
如果invoker和handler运⾏于相同的环境,可能直接把handler的回调函数的指针挂在命令结构体上,receiver可以直接调⽤handler的回调函数。很显然,不同的运⾏环境是没法这么做的。所以命令码数组是⼀个更为通⽤,封装性更好的⽅法。
⾯向对象的命令模式并没有提及到命令的消息队列,也没有提及命令码数组。消息队列本⾝并不是命令模式的⼀部分,⽽是在C语⾔实现⾥经常会⽤到的,特别是命令和执⾏不再同⼀个运⾏环境。命令码数组对于⾯向对象来说可以⽤多个⼦类来实现,所以也不体现出来。
list.h  实现如下 c语⾔设计模式代码完整实现-基础(链表实现)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "list.h"
/*
向对象发送⼀个请求,但是并不知道该请求的具体接收者是谁,
具体的处理过程是如何的,只知道在程序运⾏中指定具体的请求接收者即可,
对于这样将请求封装成对象的我们称之为命令模式。所以命令模式将请求封装成对象,
以便使⽤不同的请求、队列或者⽇志来参数化其他对象。同时命令模式⽀持可撤销的操作。
命令模式的C语⾔实现也是⾮常显性的。
集成电路设计流程
命令发送⽅不通过直接调⽤的⽅式,⽽是通过发⼀个命令消息给接收⽅,
让接收⽅执⾏操作。C语⾔⾥采⽤命令模式的最常见的原因是核间通信,进程间交互。
如果是核间通信,通常是把命令按协定的格式封装在消息数据包⾥。
如果是进程间通信,通常封装成⼀个结构体,把参数带过去。命令的通道通常是队列。
*/
typedef enum
{
CMD_1 = 0,
CMD_2 = 1,
CMD_MAX,
}E_COMMAND_MODE_INEX;
#define CMD_LEN 256
struct cmd_msg
{
struct list_head list;
int cmd_code;
char buf[CMD_LEN]; //如果是不同环境的,只能⽤buffer数组,否则可以⽤指针
};
struct list_head command_global_list; //cmd_queue /cmd_list
//命令的实际处理函数
typedef int(*cmd_func)(char* buf);
struct cmd_handle
{
int cmd_code;
cmd_func handle_func;
};
int cmd1_handler(char* buf)
{
printf("cmd1_handler.\n");石墨密封圈
return 0;
}
}
int cmd2_handler(char* buf)
{
printf("cmd2_handler.\n");
return 0;
}
/*
命令码数组:
命令码数组有两种⽅式,⼀种是将命令码作为数据的索引。
另外⼀种情况是由于命令码太⼤,有⼀些特殊的规定,没法作为索引。
所以在⼀个结构体⾥封装命令码和handler,最后实现⼀个结构体数据,
这个在复杂的内核实现⾥会出现。
下⾯是简单的命令码,就是函数指针数组。
*/
struct cmd_handle cmd_table[] =
{
{ CMD_1, cmd1_handler },
{ CMD_2, cmd2_handler },
};
/*
Invoker和receiver
Invoker的⼯作很简单,填充命令命令封装结构体,将其放⼊队列。
*/
/*
fill cmdcase and add cmd to queue
*/
int invoker(struct cmd_msg* pcmd_case)
{
if (NULL == pcmd_case)
{
printf("fill cmdmsg error.\n");
}
//send cmd_case to queue
list_add_tail(&pcmd_case->list, &command_global_list);
printf("send cmd_case%d to queue.\n", pcmd_case->cmd_code);
return 0;
}
#define cmd_queue_empty 0
#define cmd_queue_notempty 1
typedef enum
{
CMD_QUEUE_EMPTY = 0,
CMD_QUEUE_NOT_EMPTY,
CMD_QUEUE_MAX
}E_CMD_QUEUE_STATUS;
/*
PPPOE 协议
思想是: 检查command_global_list中的queue是否为空,不为空就是获取⾥⾯的cmd_msg内容,然后根据cmd_code 遍历cmd_table来handler它,处理完了记得要将cmd从列表中去掉
*/
E_CMD_QUEUE_STATUS cmd_receiver()
{
struct cmd_msg *cmd_case;
struct list_head* node;
unsigned int index = 0;
E_CMD_QUEUE_STATUS cmd_queue_status ;
E_CMD_QUEUE_STATUS cmd_queue_status ;
int is_handler = 0; //1 is handler
//if (list_empty(command_))
if ((command_) == NULL)
{
printf("list=0x%x.\n", &command_global_list);
printf("pre_list=0x%x.\n", &command_global_list.prev);
printf("next_list=0x%x.\n", &command_);
cmd_queue_status = CMD_QUEUE_EMPTY;
return cmd_queue_status;
}
//get cmd_case from queue while queue is not empty
node = command_;
cmd_case = list_entry(node, struct cmd_msg, list);
for (index = 0; index < sizeof(cmd_table) / sizeof(cmd_table[0]); index++)    {
if (cmd_case->cmd_code == cmd_table[index].cmd_code)
电梯维保系统{
cmd_table[index].handle_func(cmd_case->buf);
农用保水剂is_handler = 1;
}
}
if (is_handler)
{
printf("valid cmd%d.\n\n", cmd_case->cmd_code);
}
else
{
printf("invalid cmd%d.\n\n", cmd_case->cmd_code);
}
//delete data form queue.
list_del(node);
cmd_queue_status = CMD_QUEUE_NOT_EMPTY;
return cmd_queue_status;
}
/*命令队列有很多形态,⽐如IPC通道,
⽤信号量,也能不要队列直接调⽤,
总之就是让命令交到reciever⼿上然后分发调⽤handler。
*/
int main()
{
struct cmd_msg cmd1_case;
struct cmd_msg cmd2_case;
E_CMD_QUEUE_STATUS cmd_queue_status;
//init queue
init_list_head(&command_global_list);
//fill command
memset(&cmd1_case, 0, sizeof(cmd1_case));
d_code = CMD_1;
invoker(&cmd1_case);
memset(&cmd2_case, 0, sizeof(cmd2_case));
d_code = CMD_2;
invoker(&cmd2_case);
invoker(&cmd2_case);
//处理cmd,这个处理在实际中可能在另⼀个线程中
while (1)
{
cmd_queue_status = cmd_receiver();
if (cmd_queue_status == CMD_QUEUE_EMPTY)
{
break;
}
矿泉水瓶盖
}
getchar();
return 0;
}
模式实现总结
命令模式也是C语⾔实现的显性的设计模式,⾓⾊分为发布命令的invoker,分派命令的receiver和实际执⾏命令的handler。命令队列和命令码数组是核⼼的辅助元素。命令码数组⽬前只有两种类型。命令队列的实现类型就⾮常多,甚⾄未必是队列形式,需要设计⼈员根据经验把握。

本文发布于:2024-09-22 15:29:02,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/3/183374.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

下一篇:QtpostEvent
标签:命令   模式   队列   封装
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议