函数指针,领域语言,乱弹

rel="File-List" href="file:///G:%5Ctmp%5Cmsohtml1%5C01%5Cclip_filelist.xml">

函数指针,领域语言,乱弹

 

实现一个模块ct,该模块的需求如下:

 

ct的收到数据后,进行处理,并将结果输出可能有三个不同的地方,我们称之为AM,BM,CM(称为模块A, 模块B, 模块C)。

并且在模块的运行过程中,有可能改变输出的位置(丛输出到模块A变更为输出到模块B)

 

模块A, 模块B, 模块C会给ct发送反馈信息,收到这些信息之后,ct将进行Lcd显示,Led点灯,buzzer鸣动。根据反馈的信息不同,以上三个信息也会不同。

 

Ct在未收到反馈之前,再次收到数据的话,将这些数据丢弃。(也有可能缓存起来,收到反馈之后,再处理缓存的数据)

 

设计时的考虑:

1, 由于输出有3个不同的地方,我们很自然的想到抽象。将输出的动作抽象为统一的接口。这样ct模块的绝大多数处理逻辑将不会意识到具体的输出地。当然,一部分的处理逻辑需要了解并控制输出到哪个模块。但是,我们想得到的是集中控制。这种控制权要集中在一个或者尽肯能少函数中。这种控制逻辑越混乱,代码出错的可能性就越高。

2, Ct在收到数据时,要进行Lcd显示,Led点灯,buzzer鸣动处理。并且根据反馈的信息不同,以上三个信息也会不。由于这种处理是相当容易变化的,(lcd显示什么内容?哪个led需要点亮,需要buzzer多长时间?等),所以我们不能将这种易变的,细节的内容放进代码中。而应该将其放到外部配置文件或数据中。

3, Ct模块很明显有根据状态的不同,作不同的处理的逻辑。状态模式能够排上用场。

 

实现时的考虑:

1, 抽象出输出功能的接口。很自然,函数指针。在更改输出位置时,只需要重新设置该指针就可以了。

2, Lcd显示,Led点灯,buzzer鸣动的控制信息,我们很容易想到xml配置文件,xml文件稍嫌复杂,有点儿大材小用了。不过这种简单的功能我们可以使用表达力更强的领域语言来描述。也就是说,我们站在更高级的抽象层上进行思考,设计,实现。形如DSV(Delimiter-separated values)字符串的格式就可以胜任该工作。有变化时,直接修改DSV字符串。体现了将细节放进元数据,将抽象放进代码的思想。

3, Ct模块的状态。有基于表的状态迁移的实现和基于Robert C. Martin的三层状态机实现。考虑到仅有两个状态,就不用劳驾复杂的三层状态机了。体现了实现复杂度和问题域间的一种权衡。

 

下面是基于这种考虑的一个架子性实现。

 

#include <string.h>

 

typedef unsigned char  UC ;

typedef unsigned short US ;

typedef unsigned long  UL ;

typedef int          sMessage ;

typedef enum

{

       CT_STS_IDLE = 0 ,

       CT_STS_PROC

} CT_STS ;

 

typedef UL ( * PFCMEVICEHANDLER ) ( sMessage * pMessage ) ;

 

static PFCMEVICEHANDLER gpfcmeviceHandlers ;

 

static UL am_Handler ( sMessage * pMessage ) ;

 

static UL bm_Handler ( sMessage * pMessage ) ;

 

static UL cm_Handler ( sMessage * pMessage ) ;

 

static PFCMEVICEHANDLER gpfnAMHandlers =  am_Handler ;

static PFCMEVICEHANDLER gpfnBMHandlers =  bm_Handler ;

static PFCMEVICEHANDLER gpfnCMHandlers =  cm_Handler ;

 

 

typedef PFCMEVICEHANDLER    PFNMATRIXHANDLER ;

/* [IDLE .. PROCESSING] */

static UL idle_Handler ( sMessage * pMessage ) ;

static UL proc_Handler ( sMessage * pMessage ) ;

 

static PFNMATRIXHANDLER     gMatrixHandler[] =

{ idle_Handler , proc_Handler } ;

 

static CT_STS gSts ;

 

 

/* LCDLED、ブザーの処理*/

/* 次のフォーマットで表す*/

/* [LCD MSG]: [LED OK/NG]: [TIME]: [BUZZA ON]: [OFF]: [CNT] */

#define LLB_SEPARATOR  ": "

#define LLB_SCENARIO_1 "NULL: OK: 100: 200: 0: 1"

#define LLB_SCENARIO_2 "MSG1: NG: 100: 200: 200: 3"

#define LLB_SCENARIO_3 "MSG2: NG: 100: 200: 200: 3"

 

typedef struct LcdLedBuzzaCtrlInfo

{

       UL      ulLcdMessage     ;

       UC      ucLedType        ;

       UC      ucLedTimeMs      ;

       US       usReserve1       ;

       US       usBuzzaOnTimeMs  ;

       US       usBuzzaOffTimeMs ;

       US       usBuzzaCnt       ;

       US       usReserve2       ;

} LcdLedBuzzaCtrlInfo ;

 

static LcdLedBuzzaCtrlInfo parsedl( const char * pdl ) ;

static void                processdl( LcdLedBuzzaCtrlInfo * info ) ;

 

 

int _tmain(int argc, _TCHAR* argv[])

{

       gSts = CT_STS_IDLE ;

 

       sMessage s ;

 

       // default

       gpfcmeviceHandlers = gpfnCMHandlers ;

 

       // sometime change to am

       gpfcmeviceHandlers = gpfnAMHandlers ;

 

       // sometime change to bm

       gpfcmeviceHandlers = gpfnBMHandlers ;

 

 

       // gpfcmeviceHandlersを利用して、操作を行い

       gpfcmeviceHandlers( &s ) ;

      

       processdl ( &parsedl(LLB_SCENARIO_3) ) ;

 

       return 0;

}

 

UL am_Handler ( sMessage * pMessage ) { printf("am_Handler") ; return 0 ; }

 

UL bm_Handler ( sMessage * pMessage ) { printf("bm_Handler") ; return 0 ; }

 

UL cm_Handler ( sMessage * pMessage ) { printf("cm_Handler") ; return 0 ; }

 

UL idle_Handler ( sMessage * pMessage )

{

              // pMessageが入力メッセージの場合、

              // gpfcmeviceHandlersを呼び出す

              // Procに遷移

       return 0 ;

}

UL proc_Handler ( sMessage * pMessage )

{

              // pMessageが入力メッセージの場合、捨てる

              // pMessageがレスポンスメッセージの場合、Idleに遷移

       return 0 ;

}

 

 

LcdLedBuzzaCtrlInfo parsedl( const char * pdl )

{

       LcdLedBuzzaCtrlInfo info ;

      

       char * pLCDMsg ;

       char * pLEDType ;

       char * pLEDTime ;

       char * pBuzOnTime ;

       char * pBuzOffTime ;

       char * pBuzCnt ;

 

       char scenario[128] ;

 

       memset ( &info , 0 , sizeof(info) ) ;

       strcpy( scenario , pdl ) ;

 

       pLCDMsg     = strtok( scenario , LLB_SEPARATOR ) ;

       pLEDType    = strtok( NULL     , LLB_SEPARATOR ) ;

       pLEDTime    = strtok( NULL     , LLB_SEPARATOR ) ;

       pBuzOnTime  = strtok( NULL     , LLB_SEPARATOR ) ;

       pBuzOffTime = strtok( NULL     , LLB_SEPARATOR ) ;

       pBuzCnt     = strtok( NULL     , LLB_SEPARATOR ) ;

 

       // check

        if ( (!pLCDMsg) ||

                (!pLEDType) || (!pLEDTime) ||

                (!pBuzOnTime) || (!pBuzOffTime) || (!pBuzCnt)

              )

        {

               printf("error/n") ;

               return info ;

        }

 

        printf("LCD->%s, LED->%s:%s, Buzza->%s:%s:%s/n" ,

               pLCDMsg ,

               pLEDType , pLEDTime ,

               pBuzOnTime , pBuzOffTime , pBuzCnt       ) ;

      

        return info ;

}

void processdl( LcdLedBuzzaCtrlInfo * info )

{ }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值