C语言实现设计模式—命令模式

C语言设计模式——命令模式

好处:让代码清晰明了,容易添加和删除,易维护。
哪些地方会用到命令模式?(列出几个常见的例子)
1、按键处理,每个按键按下得到一个索引(指的就是命令),一个按键对应一个处理函数。按键处理命令模式

2、协议解析(串口,网口,CAN,等等);以串口为例简单说明一下,比如有如下协议:http类型解析(html,jpg,jpeg…)

帧头命令数据长度数据内容校验帧尾
1字节1字节2字节n字节2字节1字节

命令1:0x01 温度

命令2:0x02 湿度

命令3:0x03 光照强度

传统的实现方式如下:(伪代码)

static uint8_t parse(char *buffer, uint16_t length)
{
  uint8_t head = buffer[0];
  uint8_t cmd = buffer[1];
  uint16_t len = (buffer[2] << 8) | buffer[3];
  uint16_t crc = CRCCheck(buffer, length - 3);
  uint8_t tail = buffer[length - 1];
 
  if((head != xxx) && (tail != xxx) && (crc != ((buffer[length - 3]) << 8) | buffer[length - 2]))
  {
    return 0;
  }
 
  switch(cmd)
  {
  case 0x01:
    int temperatue = *(int *)&buffer[4];
    printf("temperatue = %d\n", temperatue);
    break;
  case 0x02:
    int humidity = *(int *)&buffer[4];
    printf("humidity = %d\n", humidity);
    break;
  case 0x03:
    int illumination= *(int *)&buffer[4];
    printf("illumination = %d\n", illumination);
    break;
  default:
    printf("parse error\n");
    break;
  }
 
  return 1;
}

通过这段伪代码可以看出代码结构的一些问题,如果要添加更多的命令,势必需要向switch case语句中加入更多的case语句。使得解析函数越来越臃肿。当然我们可以使用如下方式规避一些问题:(伪代码)

命令模式优化

命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
优点: 1、降低了系统耦合度。 2、新的命令可以很容易添加到系统中去。
缺点:使用命令模式可能会导致某些系统有过多的具体命令类。
使用场景:认为是命令的地方都可以使用命令模式,比如: 1、GUI 中每一个按钮都是一条命令。 2、模拟 CMD。

UML 用例说明

在这里插入图片描述

实现流程

在这里插入图片描述

C语言实现的命令模式核心数据结构是命令。发布命令的是invoker,多个invoker将命令封装起来,送到队列里。有一个函数或者线程称为receiver,检查队列里是否有没有处理的命令。由receiver负责调用各个handler。另外一个被经常使用的辅助数据结构是命令码数组,在如果invoker和handler运行于不同的环境,这种做法几乎是必选,如核间通信,内核和应用态通信。命令码作为索引,handler调用函数作为元素,Receiver根据不同的命令码调用handler。

command.h

#ifndef __COMMAND_H
#define __COMMAND_H


#include <rtthread.h>
#include "lw_oopc.h"
#include <stdbool.h>

typedef struct rz_command_t rz_command_t;

typedef struct rz_command_param_def{
  uint8_t head;
  uint8_t cmd;
  uint16_t length;
  uint8_t* data;
}rz_command_param_t;

typedef struct rz_command_package_entry_def{
  uint8_t cmd;
  bool (* handle)(rz_command_t * t);
} rz_command_package_entry_t;

CLASS(rz_command_t)
{
	char *name;
	 rz_command_param_t param;
	 bool (*rz_command_parse)(rz_command_t * pobj, int cmd);
	 void (*init)(rz_command_t * pobj);
};

void rz_command_obj_init(void);
rz_command_t * rz_command_obj_get(void);
#endif

command.c

#include "Command.h"
 
static rz_command_t rz_command_obj;

rz_command_t * rz_command_obj_get(void)
{
    return (rz_command_t *)&rz_command_obj;
}


static bool parse_temperature(rz_command_t * t)
{
    rt_kprintf("%s\r\n", __FUNCTION__);
	return true;
}
static bool parse_humidity(rz_command_t * t)
{
	rt_kprintf("%s\r\n", __FUNCTION__);
	return true;
}
 
static bool parse_illumination(rz_command_t * t)
{
 
    rt_kprintf("%s\r\n", __FUNCTION__);
	return true;
}

static const rz_command_package_entry_t package_items[] =
{
  {0x01, parse_temperature},
  {0x02, parse_humidity},
  {0x03, parse_illumination},
  {0xFF, NULL},
};

bool rz_command_parse(rz_command_t * pobj, int cmd)
{
	for(uint8_t i = 0; i < sizeof(package_items)/sizeof(package_items[0]); i++){
		if((cmd == package_items[i].cmd) && (NULL != package_items[i].handle)){ 
			if(true == package_items[i].handle(pobj)){
				return true;
			}
		}
	}
   return false;
}

static void command_init(rz_command_t *t)
{
	t->name = "Command";
	
}

void rz_command_obj_init(void)
{
    rz_command_t * polt = rz_command_obj_get();

    rz_command_t_ctor(polt);
    polt->init(polt);
}
CTOR(rz_command_t)
FUNCTION_SETTING(rz_command_parse, rz_command_parse);
FUNCTION_SETTING(init, command_init);
END_CTOR

main

int Command(void)
{
   
   rt_uint8_t count;
   rz_command_obj_init();
   rz_command_t * pobj = rz_command_obj_get();

    for(count = 0 ; count < 3 ;count++)
	{       
		pobj->rz_command_parse(pobj,count);
		rt_thread_mdelay(100);
	}
   
    return 0;
}
MSH_CMD_EXPORT(Command, RT-Thread first Command sample);

总结

  1. 在命令模式中,将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作模式或事务模式。
  2. 命令模式的主要优点在于降低系统的耦合度,增加新的命令很方便,而且可以比较容易地设计一个命令队列和宏命令,并方便地实现对请求的撤销和恢复;其主要缺点在于可能会导致某些系统有过多的具体命令类。
  3. 命令模式适用情况包括:需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互;需要将一组操作组合在一起,即支持宏命令。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值