使用表驱动技术优化程序结构

DRG_DIP 2.0时代医院程序结构转型与数据结构优化研究 本研究深入剖析了 DRG_DIP 2.0 环境下医院程序结构调整策略与数据编程语句调整的关键要点。通过对 DRG_DIP 2.0 编码体系变革的详细阐述,明确了其在数据源、编码规则和分组逻辑等方面与 1.0 版本的显著差异,以及这些差异对医院程序结构的潜在影响。在医院程序结构调整策略上,提出了组织架构适应性变革,成立专项改革小组并明确各部门职责分工,有效推动了 DRG_DIP 2.0 改革在医院的落地实施。医疗服务流程再造,基于临床路径优化和强化多学科协作模式,提高了医疗服务质量和效率,降低了医疗成本。 阅读详情

1.前言

所谓的表驱动技术实际上是一种回调函数(callback function),它能够使调用者在完全不知道细节的情况下完成复杂的操作。使用这种技术不但可以使你的代码更加紧凑,还能够降低各个模块的耦合程度,优化程序结构。

表驱动的适用范围很广,无论是底层驱动开发,还是上层通讯都可以用到,甚至Microsoft著名的MFC中的消息映射也使用了这一技术。本文结合一个例子介绍了如何在实际工程中使用该技术。

2.简化你的switch-case

试想一下,如果你的程序需要处理这么一种情况:你会不停的接收到各种各样的外部请求,然后需要在自己的函数中针对不同请求作出相应的反应,你该怎么做?

最直接的想法无非是使用分支语句来调用不同的函数,比如下面的代码:

BOOL DispatchFunction(COMMANDMSG CommandID)

{

    switch(CommandID)

    {

    case COMMAND1:

       {

           Func1();

           break;

    }

case COMMAND2:

    {

       Func2();

       break;

    }

……

default:

    {

       return FALSE;

    }

}

return TRUE;

}

怎么样?很简单是吧。当然,如果处理的规模小,这么做是正确的方法。然而如果你面对的是几十种甚至上百种请求呢?设想一个有着上百个分支的程序,天呐,光是想头都快炸了……

如果你是个有一定经验的程序员,你可能会考虑到使用宏来将每个case分支简化成一行。的确,这也是不错的方法,但是治标不治本。能不能找到一种方法将一个上百行的函数简化到区区不到十行呢?

答案是肯定的。我们可以构建一个数组,数组中每个元素存放着外部请求和对应操作的映射关系。现在,问题就被简化成在一个循环当中遍历一个数组,抽取请求,然后执行操作。像刚才的程序就可以这么写:

BOOL DispatchFunction(COMMANDMSG CommandID)

{

    for (int i = 0; i < nItemCount; i++)

{

    if (DispatchTable[i].KeyVal == CommandID)

    {

       *DispatchTable[i].HandleFunc();

       return TRUE;

}

}

return FALSE

}

如何,我们刚刚将一个繁冗不堪的函数变成了一个干净整洁,区区只有不到十行代码的程序!这只是一个开始,使用表驱动你还可以看到更多好处。

在上面的程序中,DispatchTable是一个结构体数组,也就是我们这个函数的驱动表。KeyVal是键值,HandleFunc是指向函数的指针,它们被包含在一个结构体中,并存放在驱动表里。函数通过访问表中的每个元素与外部请求CommandID进行比对,如果一致,则通过函数指针来调用相应的函数。这样,我们所作的工作就与刚才那个上百行的分支函数是一样的了。

另一方面,你可能还注意到这种写法会带来额外的好处。如果增加了新的请求方式,或者必须改写旧有的请求关系,我们根本不需要修改函数DispatchFunction,只要维护这个驱动表DispatchTable就可以完成这个工作了。因为这个函数甚至不清楚它自己干了些什么。它就像一个盒子,将驱动表装载到里面,然后执行一些简单的操作。你甚至能够在运行时替换掉里面的驱动表,从而达到动态装载的目的。

接下来我们来看一个例子,这种技术可以帮助我们完成什么样的任务。

3.例子:使用表驱动编写你的命令解释器

在通讯程序中,命令解释器是一个必不可少的组件。我们将底层收上来的报文加以拆分,提取中间的命令字段交给命令解释器来解释,之后执行各种操作。由此可见,命令解释器本身就是一个具有多分支的程序,正好适合采用表驱动。

这里举的例子是在笔者参与的实际工程中使用的命令解释器。首先必须定义函数指针和驱动表中元素的结构体,代码如下:

typedef void(CCmdTarget::*HANDLEFUNC)(PBYTE lpBuffer);

typedef struct _DISPATCHITEM

{

    BYTE m_byKeyVal;

    HANDLEFUNC m_HandleFunc;

}DISPATCHITEM, *PDISPATCHITEM;

由于相应的执行函数位于窗体中,因此函数指针类型前面带有CCmdTarget前缀。m_byKeyVal代表键值,也就是报文中提取出的命令段。m_HandleFunc是对应的执行函数指针。

命令解释器的代码如下:

BOOL CSCIComm::CommandInterpreter(BYTE byCommandID, PBYTE lpBuffer)

{

    for (int i = 0; ; i++)

    {

        if (m_DispatchTbl[i].m_byKeyVal == COMMPTL_RESERVED_DISPATCHTBLEND)

        {

            return FALSE;

        }

         else if (m_DispatchTbl[i].m_byKeyVal == byCommandID &&                                                  m_DispatchTbl[i].m_HandleFunc)

        {

            (m_pPortOwner->*m_DispatchTbl[i].m_HandleFunc)(lpBuffer);

            return TRUE;

        }

    }

}

 

 

这部分代码跟上一节最后提到的那个函数非常类似,其中m_DispatchTbl是命令解释器CommandInterpreter的驱动表。所不同的是,为了提升程序的灵活度,在for循环中没有边界检查。这样,为了避免程序死循环,我们在驱动表的最后还要加上终止标识,也就是COMMPTL_RESERVED_DISPATCHTBLEND。另外在C++中,由于成员函数的调用实际上前面会存在隐含的this指针,使用函数指针调用同样如此。所以在这里增加了一个成员变量m_pPortOwner用来代替this指针调用这些成员函数。

通过使用表驱动来编写命令解释器,可以得到很多好处:

首先是代码的简洁性,这个优点不言自明。

其次,你可以将底层代码和协议层分离。命令解释器属于下层,它会反上来很多命令,然后加以派送,但是它根本不需要关心该如何处理这些问题,因为只要加载驱动表然后“按图索骥”就好了。

最后,你甚至可以在程序运行中动态装载驱动表,从而达到不停止运行就能改变通信协议的目的,这一点提供了极高的灵活性。

你看,一个基本的表驱动结构优点多多而且实现起来也很简单。我们需要的额外操作只是构建这个驱动表并且对其加以维护而已。接下来,我会另外介绍一些小技巧来使这部分程序获得更大的方便性和灵活性,尽管这部分内容并不直接属于表驱动的范畴。

4.还可以更加灵活

前面提到,表驱动本身需要驱动表的构建。关于构建驱动表,你可以在类的构造函数中或者某个窗体的OnCreate或是OnInitalUpdate中,构建一个静态的数组,然后顺带进行初始化赋值。

但是,如果你考虑到代码的可读性,以及你的代码和其他代码的交互性。比如解释层和底层是由你来做,但是协议层是别人来做。你就不得不考虑如何能让别人更方便的构建想要的驱动表。这里提供一些小技巧可以作为参考。

首先,你可以定义一些宏,采用宏的方式将命令段和执行函数映射到这张表里。当然它们会标识有起始和结束的标志。在例子中定义如下:

#define DISPATCH_MAP_BEGIN(thePointer)            /

    if (!*thePointer){                            /

       static const DISPATCHITEM _DispatchTbl[] = /

       {

#define DISPATCH_ITEM_MAP(byKeyVal, pHandleFunc)  /

    { (BYTE)byKeyVal, (HANDLEFUNC)pHandleFunc },

 

#define DISPATCH_MAP_END(thePointer)              /

    { COMMPTL_RESERVED_DISPATCHTBLEND, NULL }     /

    };                                         /

    *thePointer = (PDISPATCHITEM)&_DispatchTbl[0]; /

    }

 

其中,DISPATCH_MAP_BEGIN和DISPATCH_ITEM_END分别代表映射开始和结束。它们的作用就是建立一个静态的常量数组,然后在映射最后写入结束标志,并且将这个静态的数组的地址传递给数组指针,也就是thePointer代表的对象。

而DISPATCH_ITEM_MAP就是负责命令字和执行操作的映射,它会把二者写入建立好的静态数组中。

具体的使用如下所示:

PDISPATCHITEM* pointer = m_SCIComm.GetDispatchTbl();

DISPATCH_MAP_BEGIN(pointer)

    DISPATCH_ITEM_MAP(COMMPTL_REQ_INPUT, &CMainFrame::TrackParamHandler)

    DISPATCH_ITEM_MAP(COMMPTL_REQ_OUTPUT, &CMainFrame::TrackParamHandler)

    DISPATCH_ITEM_MAP(COMMPTL_MDY_INPUT, &CMainFrame::ModifyInputHandler)

    DISPATCH_ITEM_MAP(COMMPTL_MDY_INPUT_E2, &CMainFrame::ModifyInputHandler)

    DISPATCH_ITEM_MAP(COMMPTL_IDLECYC_MAX, &CMainFrame::SaveIdleCycleMaxHandler)

        ……

DISPATCH_MAP_END(pointer)

怎么样,是不是清楚多了?而且你会否有似曾相识的感觉,很像MFC中消息映射的格式?没错,实际上MFC中消息映射也是一个典型的表驱动应用。

另外,介绍的例子中命令解释器接收的参数byCommandID使用的是BYTE类型。为了提高可扩展性,你完全可以向其中传入一个结构体指针,这样就可以容纳更多的信息。但是,相对的,关于比较操作也必须传入一个回调函数,利用其进行比对操作。对于执行函数也是同样的道理。由于执行函数进行的操作千差万别,参数和返回值很有可能不一致。我们可以用一个结构体指针来替代固定的类型,这样就具有更大的灵活性了。

 

5.总结

表驱动技术是一种可以使你的代码更简洁,结构更加灵活的技术,最适用于多分支的函数当中。另外,我们可以配合驱动表编写一些可以灵活配置的宏,这样能让你的程序修改起来更加得心应手。

23、程序结构与设计优化 本文详细介绍了程序设计中的核心原则与优化方法,包括松耦合与高内聚、代码复用、数据抽象与不透明类型、静态库与动态库的选择、链接机制等内容,并通过一个质数测试程序的完整示例,展示了如何将这些原则应用于实际开发。同时,文章还探讨了性能优化、错误处理以及模块化设计的最佳实践,帮助开发者构建高质量、可维护、可扩展的软件系统。 阅读详情

相关推荐

26、菜单驱动程序:实现用户友好交互的程序结构

本文详细介绍了菜单驱动程序的概念、实现方式及其在实际开发中的应用。通过清晰的结构和示例代码,帮助读者理解如何构建用户友好的命令行交互程序,并讨论了设计原则、调试测试方法以及优化与扩展策略。此外,还展示了如何将菜单驱动程序与图形界面结合,提升用户体验。

cc789的博客 100

表驱动法(Table-Driven Approach)

但将2位的编号转换为1位的键值,可能过于复杂或没有规律,最合适的方法是建立一个保存该转换关系的索引表。如果按照这种方法写下去,那么在我的每一个函数里面,都必须作如此多的判断,写出的代码肯定很长,并且每一次处理,都要作许多次判断之后才找到正确的处理函数,代码的执行效率也不高。,表驱动的核心是key-handler,拿某个key去对应某个handler,只要条件符合key,那么就执行对应的handler。使用索引的时候,先用一个基本类型的数据从一张索引表中查出一个键值,然后再用这一个键值查出你需要的主数据。

qq_45885788的博客 2401

实现LCD19264显示驱动技术详解

LCD19264显示技术源自于液晶显示(Liquid Crystal Display,LCD)的基本原理。从最初的单色显示到现在的彩色、高清显示,技术的进步使得LCD显示越来越贴近我们的生活。19264这个参数代表了屏幕的分辨率,即192×64个像素点,这种分辨率在小型显示领域中应用广泛,如电子手表、计算器等。HZDotReader.exe 是一个功能强大的汉字字模生成与编辑工具。用户可以从它的官方网站或授权的分发渠道下载最新版本。

weixin_33298352的博客 1278

表驱动法-灵活编程范式

表驱动法是一种编程范式,通过数据结构(表)替代条件分支判断,实现数据与逻辑分离。其核心是条件-处理;映射关系抽象为表格,包含表结构设计、查表逻辑和执行逻辑三部分。典型实现包括静态结构体数组式(编译期确定表项,适合固定场景)和链表式(运行时动态调整,适合灵活需求)。示例展示了设备命令解析场景中,如何用结构体数组存储命令映射,通过查表快速定位处理逻辑,避免了传统if-else的维护难题,提升代码可扩展性。表驱动法尤其适用于多分支、业务规则频繁变化的场景。

eatbaozi的博客 1105

开源:AI+无人机巡检系统项目调研

本文系统梳理了主流开源无人机巡检技术栈,涵盖飞控系统(PX4/ArduPilot)、地面站软件(QGroundControl)、AI视觉识别(VisDrone/MPID/CPLID数据集)、三维重建(OpenDroneMap/COLMAP)和仿真模拟(AirSim/Gazebo)五大领域。通过对比各项目的技术特点、开发语言、开源协议及商用友好度,为无人机巡检产品开发提供完整的技术选型参考。重点推荐PX4飞控、DroneKit开发API等商用友好项目,同时分析了GPL/AGPL协议项目的开源要求。

lovehu6686的博客 2455

Tessent ICL语法详解:如何高效定义SIB、TDR和TAP模块

本文深入解析Tessent ICL语法,指导如何高效定义SIB、TDR和TAP模块以构建芯片测试网络。通过实战代码示例,详细阐述了各模块的端口声明、接口角色与核心寄存器定义,并提供了顶层集成连接方法与调试技巧,帮助DFT工程师精准描述测试仪器拓扑,提升Tessent工具链使用效率。

silver的专栏 494

【知识分享】C语言中的设计模式——表驱动模式

表驱动本身是强烈依赖于数组结构,可以是一维数组,也可以是多维数组,然后根据该数据的分布式结构进行数据索引。即使是使用一维数组,也是通过数组下标索引到对应的数据,从索引这个角度来看,是Key-Value这种键-键值的对应关系,像极了在表格中查找数据(通过行和列找到对应的格子),所以称之为表驱动。............

知识噬元兽的博客 3526

自适应滤波算法综述

自适应滤波算法综述

xdzhujy的博客 5万+

一文讲懂表驱动法

什么是表驱动法?是一种编程模式,从表里查找信息而不使用逻辑语句(if 和case)。事实上,凡是能通过逻辑语句来选择的事物,都可以通过查表来选择。对简单的情况而言,使用逻辑语句更为容易和...

架构精进之路 3404

Cursor概述及环境配置

Cursor 是一款基于 AI 的代码编辑器,支持 VS Code 配置迁移和 Java 开发环境配置。主要功能分为 Cursor Settings(AI 相关设置)和 Editor Settings(基础编辑器设置)。用户可通过一键导入或手动方式迁移 VS Code 配置,配置包括主题、扩展和快捷键等。对于 Java 开发,需配置 JDK 和 Maven 路径,并安装 Java 扩展插件以获得完整开发体验,如代码补全、调试和 Maven 项目管理。此外,Cursor 支持汉化配置,用户可安装中文语言包切换

Knight 3558

UE 动态获取 资源缩略图 下载到本地或返回图片信息

UE 动态加载资源缩略图 返回图片信息或保存到本地

qq_46080252的博客 1939

表驱动

<br />一,什么是表驱动 <br />  表驱动,又称之为表驱动法、表驱动方法。 <br />  “表”是几乎所有数据结构课本都要讨论的非常有用的数据结构。表驱动方法出于特定的目的来使用表,程序员们经常谈到“表驱动”方法,但是课本中却从未提到过什么是"表驱动"方法。表驱动方法是一种使你可以在表中查找信息,而不必用很多的逻辑语句(if或Case)来把它们找出来的方法。事实上,任何信息都可以通过表来挑选。在简单的情况下,逻辑语句往往更简单而且更直接。但随着逻辑链的复杂,表就变得越来越富有吸引力了,通过下面的

Spectacular的专栏 759

C#上位机性能优化全攻略:彻底解决界面卡顿+多线程死锁+PLC数据延迟,产线实测稳定运行2年

一开始我们用的是网上找的零散优化代码,根本满足不了要求,后来花了2个月的时间,把之前27条产线的代码整理、重构、优化,做了一套这套方案上线后,连续稳定运行2年零3个月:界面响应时间稳定在50ms以内,多线程死锁率持续为0,PLC数据延迟稳定在150ms以内,系统可用率≥99.99%,帮客户一年省下了超过480万的停线损失、罚款损失和人工成本,客户第二年就把剩下的22条产线也全部交给我们做了,还介绍了3家同行。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 294

表驱动法

----------------------------------------------------------------------------------------------------------------------------- 使用表驱动技术优化程序结构           转自 http://blog.youkuaiyun.com/vector03/article

理性的幻想 2231

读懂 ABAP CDS 注解的直接、继承与派生

本文系统梳理了ABAP CDS注解的评估逻辑,重点解析直接注解(Direct)、继承注解(Inherited)和派生注解(Derived)的差异及其在CL_DD_DDL_ANNOTATION_SERVICE中的处理方式。通过视图注解@Metadata.ignorePropagatedAnnotations可调控注解传播行为,避免下游语义影响上层视图。文章还提供了基于标准表的完整示例(包含底层视图、消费视图和ABAP报告程序),帮助开发者在实际系统中验证三层注解的叠加效果与阻断机制。关键点包括:派生注解的数据

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 246

Allegro层叠中的Etch Factor-铜皮的腐蚀因子如何计算

在用Allegro进行PCB设计的时候,Cross-section中需要填入对应的信息,一般填入每层的厚度即可,如下图。当PCB需要进行仿真分析的时候,Etch-Factor这个值是必须要填写的,如下图。实际铜皮进行蚀刻的时候,Etch-Factor的值并不是标准的90度,如下图。线路层实际形状是个梯形,Etch-Factor代表的就是梯形的角度,如下图。首先输入数值,比如1,再点击Inv,最后点击tan-1,可以得到角度的值。如果tanσ=2,σ=63.4,如下图计算结果。即tanσ=1,得到σ=45。

weixin_54787054的博客 886

什么是表驱动

普通代码 ---------------------------------------------------------------------------------------------------------------------------- void msg_proc(const char *msg_type, const char *msg_buf) {

程序 = 实践 + 思考 (Programming = Practice + Thinking) 1070

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

表驱动法介绍

什么是表驱动   表驱动,又称之为表驱动法、表驱动方法。   “表”是几乎所有数据结构课本都要讨论的非常有用的数据结构。表驱动方法出于特定的目的来使用表,程序员们经常谈到“表驱动”方法,但是课本中却从未提到过什么是"表驱动"方法。表驱动方法是一种使你可以在表中查找信息,而不必用很多的逻辑语句(if或Case)来把它们找出来的方法。事实上,任何信息都可以通过表来挑选。在简单的情况

把握自己。 1812

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

嵌入式驱动学习第三周——如何优化驱动及提高驱动稳定性

在 Linux 中应用程序运行在用户空间,应用程序错误之后,并不会影响其他程序的运行,而驱动工作在内核层,是内核代码的一部分,当驱动出现问题之后,可能会导致整个系统的崩溃。所以在驱动中,需要对各种判断、预处理等进行排查等,本篇将对如何优化驱动稳定性和提高驱动效率进行学习。

qq_43419761的博客 924

如何利用LLVM控制流图分析优化程序结构:从基础到实践指南

LLVM项目作为编译器和工具链技术的集合,提供了强大的中间表示(IR)构建、代码优化及机器代码生成能力。其中控制流图(CFG)分析是优化程序结构的核心技术,能够帮助开发者理解程序执行路径、识别性能瓶颈并实现高效代码优化。本文将深入浅出地介绍LLVM中控制流图分析的基础原理、应用场景及实操方法,适合编译器开发新手和软件优化工程师学习。 ## 控制流图:程序优化的"地图" 🗺️ 控制流图是编译器

gitblog_00434的博客 780

数据驱动编程之表驱动法

原文:http://blog.youkuaiyun.com/chgaowei/article/details/6966857 本文示例代码采用的是c语言。 之前介绍过数据驱动编程《什么是数据驱动编程》。里面介绍了一个简单的数据驱动手法。今天更进一步,介绍一个稍微复杂,更加实用的一点手法——表驱动法。 关于表驱动法,在《unix编程艺术》中有提到,更详细的描述可以看一下《代码大全》,有一章专门进行描述(大

yp120yp的专栏 557

深入探讨C语言中的表驱动编程:构建高效、灵活且易于维护的程序

本文深入探讨了C语言中表驱动编程(Table-Driven Programming)的核心概念与应用。文章首先介绍了其基本原理,即通过查表代替复杂的条件判断,实现数据与逻辑分离,从而提高代码的简洁性和可维护性。随后通过三个典型案例(星期查询、状态机设计、配置文件解析)展示了表驱动的实际应用场景。文章还详细分析了数据结构选择、错误处理机制和性能优化等关键技术细节,并进一步探讨了表驱动在事件驱动架构和命令模式中的高级应用。最后强调表驱动编程是提升C语言开发效率的重要范式,能够有效应对业务复杂度,值得开发者掌握和

极客代码 262

驱动编程注意事项

1. 尽量不用全局变量,它们危害多线程操作 2. 应有一个handle(内含一个contex)贯穿驱动的每个函数,包括Init, Open等,为每个操作提供上下文。 3. 注意程序结构,要简洁,尤其是ISR函数

一码算一码 1356

Python程序结构详解:从基础逻辑到实战应用

本文系统介绍了编程中的三种基本结构:顺序、分支和循环。顺序结构是代码的默认执行方式,从上到下依次执行;分支结构通过if/elif/else实现条件判断,包括单分支、双分支和多分支;循环结构通过for和while实现重复执行,介绍了循环控制、与else配合、数据结构驱动等高级用法。文章还展示了复合结构的工程应用,如日志扫描器项目,包含嵌套结构、调试技巧和跨语言对比。掌握这些基础结构是编写高效可靠代码的关键,从语法理解到工程实践需要持续练习和优化。

2402_85519509的博客 1639

[转载]J2ME手机游戏引擎程序结构简述

J2ME手机游戏引擎程序结构简述游戏引擎的结构很多,不过基本上都是在一个游戏主循环内实现。程序里面的主循环包含了程序框架的最主要的结构体。J2me的程序一般都包含两个class文件,一个是MIDlet,一个是Displayabl...

congji3817的博客 140

车载测试实战指南:CAPL程序结构解析与事件驱动开发

本文深入解析车载测试中CAPL程序的核心结构与事件驱动开发模式。通过剖析头文件、全局变量、事件处理及自定义函数四大模块,并结合车门自动落锁功能的实战案例,系统阐述了如何构建高效、模块化的车载网络测试脚本,帮助测试工程师掌握CAPL事件驱动编程的精髓。

gitlab7runner的博客 698
上一篇: MFC下的日志系统开发
下一篇: 一个简单的实验,Java数组遍历
vector03
博客等级 码龄16年 62粉丝 16原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值