设计模式的C语言应用---编码实践(命令模式)

#include "stdafx.h"
#include <string.h>

/*
https://bbs.huaweicloud.com/blogs/109745
向对象发送一个请求,但是并不知道该请求的具体接收者是谁,
具体的处理过程是如何的,只知道在程序运行中指定具体的请求接收者即可,
对于这样将请求封装成对象的我们称之为命令模式。所以命令模式将请求封装成对象,
以便使用不同的请求、队列或者日志来参数化其他对象。同时命令模式支 持可撤销的操作。

命令模式的C语言实现也是非常显性的。
命令发送方不通过直接调用的方式,而是通过发一个命令消息给接收方,
让接收方执行操作。C语言里采用命令模式的最常见的原因是核间通信,进程间交互。
如果是核间通信,通常是把命令按协定的格式封装在消息数据包里。
如果是进程间通信,通常封装成一个结构体,把参数带过去。命令的通道通常是队列。
*/

typedef enum
{
		CMD_1 = 0,
		CMD_2 = 1,

		CMD_MAX,
}E_COMMAND_MODE_INEX;

#define CMD_LEN 256
struct cmd_msg
{
	list_head list;
	int cmd_code;
	char buf[CMD_LEN]; //如果是不同环境的,只能用buffer数组,否则可以用指针
};


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,最后实现一个结构体数据,
	这个在复杂的内核实现里会出现。

	下面是简单的命令码,就是函数指针数组。
*/

cmd_handle cmd_table[] =
{
	{ CMD_1, cmd1_handler },
	{ CMD_2, cmd2_handler },
};

/*
Invoker和receiver
Invoker的工作很简单,填充命令命令封装结构体,将其放入队列。
*/
/*
fill cmdcase and add cmd to queue
*/
int invoker(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;

/*
	思想是: 检查command_global_list中的queue是否为空,不为空就是获取里面的cmd_msg内容,然后根据cmd_code
	遍历cmd_table来handler它,处理完了记得要将cmd从列表中去掉
*/
E_CMD_QUEUE_STATUS cmd_receiver()
{
	struct cmd_msg *cmd_case;
	list_head* node;
	unsigned int index = 0;
	E_CMD_QUEUE_STATUS cmd_queue_status ;
	int is_handler = 0; //1 is handler

	if (list_empty(command_global_list.next))
	{
		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_global_list.next);
		cmd_queue_status = CMD_QUEUE_EMPTY;
		return cmd_queue_status;
	}

	//get cmd_case from queue while queue is not empty 
	node = command_global_list.next;
	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()
{
	
	cmd_msg cmd1_case;
	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));
	cmd1_case.cmd_code = CMD_1;
	invoker(&cmd1_case);

	memset(&cmd2_case, 0, sizeof(cmd2_case));
	cmd2_case.cmd_code = CMD_2;
	invoker(&cmd2_case);

	//处理cmd,这个处理在实际中可能在另一个线程中
	while (1)
	{
		cmd_queue_status = cmd_receiver();
		if (cmd_queue_status == CMD_QUEUE_EMPTY)
		{
			break;
		}
	}

	getchar();
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值