注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

LabATSS

关注自动测试软件

 
 
 

日志

 
 

LabVIEW面向对象编程—初窥门径(4):对象创建及插件(Plug-in)结构  

2018-03-30 14:58:32|  分类: LabVIEW |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |


引言:在去年年底左右(2017年11月底),由于单位业务调整,自己工作性质和内容发生较大的改变,由原先的计量参数日常运行检定改为软件维护与开发,遂开始着手对以往前同事开发完成的LabVIEW旧代码(直流电源校准/检定自动测试序列)进行重新梳理与维护,在此过程中开始边实践、边摸索的开发学习方式,应用面向对象技术(Object-Oriented Program)对旧代码进行了完全重新的改写,由于前段时间日常忙于开发工作,周末时间又要承担中年油腻男的上有老、下有小的生活“重任”,难得在春节及前后期间有一段相对空闲的时间,可以将近日的开发心得(设计思想、开发过程等)总结记录一下,以便日后回顾复习,并秉着互联共享的精神分享给大家,但是由于本人的工作内容为计量校准的测控行业,因此在实际代码开发实践时选用的案例为本行业的电学参数中的直流电源校准为样例,因此有其局限性,较为适合本行业或者是电子测试工程师们在碰到类似的代码开发情况下予以参考借鉴。

另外强烈建议大家在台式电脑上阅读该系列博客文章,缘由是:文章内容篇幅均较长,且图形化编程的截图显示效果要求大屏幕展示为宜,况且手机和平板等便携式设备易受干扰,导致碎片化式的阅读,从而恶化学习吸收效果;还请特别注意,该系列的博文并不讲述任何基础的LabVIEW面向对象概念与技术(基础部分内容将另行撰文编写),初窥门径系列重点是经典的设计原则在重构旧有面向过程代码的应用,实际发布面向对象工程代码中的填坑经验,因此并不适宜LabVIEW初学者学习, 如观看本文有云山雾里般的“恶心、头晕、眼花”等不适感,请立刻点击操作关闭页面,以免造成严重心理疾病,丧失了对LVOOP学习的浓厚兴趣!


目录:

LabVIEW面向对象编程—初窥门径(1):困惑





正文

前篇博文,我们完成了概念抽象面向对象设计(Object-OrientedDesign)后形成的不同类族(类层次),而在实际使用中,我们必然要将抽象类由具体类来实例化来取代完成细节内容的操作。因此,创建(实例化)具体类就是面向对象技术中必不可少的重要一环。

而面向过程程序中,我们直接开发依赖于具体的细节代码,因此也就不存在实例化概念的需求;而面向对象编程让我们仅仅引用对象的抽象意义,而不必考虑它的具体类型,也就是说在任何时候我们用到对象,都应该隐藏(封装)它涉及的具体实现,更进一步的讲,我们还要隐藏(封装)它涉及的具体类型,从而达到更好的替代扩展性,这也就引出了对象的使用视角和创建视角。

LabVIEW面向对象编程—初窥门径(4):对象创建及插件(Plug-in)结构 - labats - LabATSS


创建视角,我们要根据某些条件、策略来实现具体的某种特定类型的创建,并通过客户代码的属性设置(Setter)将特定类型注入到概念角色类中。并且往往是一组同类型的具体体实现同样的职能,因此往往配合的插件结构予以提供必要的扩展性。

使用视角,在使用时,我们应用依赖抽象的DIP原则,使用的都是抽象的类型和公共的接口方法,从而使得高层模块间的策略得到复用,从而达到框架复用的核心,实现代码的规模经济效益。

因此,创建视角和使用视角是两个不同变化的维度,当客户代码中使用和创建一起使用时,当某一个维度发生变化时,必然引起客户代码的修改,也就违反了面向对象设计原则中(SRP)单一职责原则。这一点我们在上篇博文中设计指标类(Specification.lvclass)时,就将实例化某个具体指标类(如负载效应指标类等)委托给对应指标策略类(SpecStrategy.lvclass)来具体的生成创建该类。

同样的我们还有应用于MAL(MeasurementAbstraction Layer)概念的测试操作类(Operation.lvclass),每个具体的测试操作类包含了相对应的具体测量标准设备和被测件设备的抽象类,例如电源负载效应测试操作类就由多功能数字表、直流电子负载和被测电源组成,一个简单的模拟设备生成创建过程如下几张图所示:


LabVIEW面向对象编程—初窥门径(4):对象创建及插件(Plug-in)结构 - labats - LabATSS

LabVIEW面向对象编程—初窥门径(4):对象创建及插件(Plug-in)结构 - labats - LabATSS

LabVIEW面向对象编程—初窥门径(4):对象创建及插件(Plug-in)结构 - labats - LabATSS

另外当我们把一组近似相同的职责类归并在在一起时,就会发现有很多的功能相同的代码片段重复出现,我们可以使用重构技术将相似的代码片段封装成为内部函数,并按照需要在类层级中进行上下移动,从而避免了重复代码也降低了过度设计。

在对具体类进行实例创建时,我们特别关注对扩展性的支持,以往面向过程编程范型中我们的扩展是通过Vi函数的动态调用来实现插件结构,Vi函数的输入输出签名模板保证调用接口的一致性;在面向对象编程范型中我们需要通过继承/多态技术来进行扩展,并且应用LSP里氏替换原则来保障接口契约的一致性。我们的需求目标中“实现被测件型号动态灵活可扩展,支持测试标准可互换”就是创建模式的目标结果。


LabVIEW面向对象编程—初窥门径(4):对象创建及插件(Plug-in)结构 - labats - LabATSS

 

我们在前面应用MAL(Measurement AbstractionLayer)与HAL(Hardware Abstraction Layer)概念对直流电源测试项目进行了概念角色抽象封装,如作为测量标准之一的数字多用表,我们将其抽象为MultiMeter.lvclass类,该类完成测量电压的行为操作,封装了不同类型的数字多用表如Ag34401A和3458A的测量电压的具体实现细节。为了实现测量标准数字多用表的替换,我们将配置替换策略通过INI配置文件来实现,实现替换配置外部灵活化、防止硬编码的僵死。

LabVIEW面向对象编程—初窥门径(4):对象创建及插件(Plug-in)结构 - labats - LabATSS

 

LabVIEW面向对象编程—初窥门径(4):对象创建及插件(Plug-in)结构 - labats - LabATSS


具体的实例化流程为:第一步查询INI文件中的配置段,读取型号和程控地址,即readFromIni.vi的功能函数实现。第二步到对应的工作目录中根据Model型号来查找<Model>.lvclass,使其实例化并向上转型(Upcast)为抽象基类完成转换。当需要进行必要的标准设备替换时,就可以简单的改写配置文件(后面还要开发配置接口界面窗口程序),完成相应的型号(Model)更替。当需要进行扩展时,直接从抽象基类MultiMeter.lvclass类进行继承,改写必要的电压测量功能抽象动态分配函数,从而实现动态热点扩展,新的具体扩展类也就可以通过配置在原先的框架下继续使用,而无需修改代码。


在落实到具体的测试驱动程序Vi库的时候,往往会碰到的是系列驱动形式,如电源Ag66XX系列驱动就对应着该系列几十种特定的型号,这时候就需要提供一个多对一的辅助功能函数(函数框图与映射文件如下图所示),帮助解决不便于直接映射,提供间接映射的问题。

LabVIEW面向对象编程—初窥门径(4):对象创建及插件(Plug-in)结构 - labats - LabATSS

 

LabVIEW面向对象编程—初窥门径(4):对象创建及插件(Plug-in)结构 - labats - LabATSS


在LabVIEW开发环境也即编辑开发时,我们进行扩展开发时,通过项目管理窗口开发新的具体型号类并继承于抽象基类,改写必要的动态分配Vi,就可以完成灵活的扩展任务,但是从运行效率、商业经济等角度考虑,我们开发的代码需要编译成可执行文件(EXE)发布给最终客户使用,大型源代码层级文件目录的组成项目结构的管理模式是无法直接提供给客户的。

另外,在提供扩展的时候,作为开发人员的我们希望能够保持兼容性,特别是二进制兼容性,即发布可执行文件后,以动态链接库(DLL)物理文件形式和插件逻辑形式提供无需重新编译安装的理想状态,理论上,我们应该讲抽象类形式接口发布为DLL,扩展时,新编代码引用接口DLL,继承后编写相应代码完成差异化实现,最后进行以扩展动态链接库(<model>.dll)的创建生成,发布以后简易配置调用相应文件,应用运行时(Run-time)对DLL功能的反射识别,即可完成积木式动态模组的替换与组合,从而形成支持全新扩展新型号的测控程序。

但是目前的LabVIEW还不具备这样的代码生成编译技术,可执行文件只是个单一独立的大文件平面(8.6版本之前)或层级存储库,缺少命名空间导致代码发布时的文件命名冲突;项目管理方式也尚不支持多项目(*.proj)整合开发;二进制项目库包(lvlibp)只能作为顶层封装接口使用,无法进行公开类型继承扩展;发布源代码方式会导致部分代码重复输出;以上也正是目前LabVIEW NXG准备重点解决的大型软件工程化的问题。但是截至到2018年2月底的LabVIEW NXG 2.0版本中还是没有完美提供二进制兼容的GLL(Graphtic Link Lib)。

LabVIEW面向对象编程—初窥门径(4):对象创建及插件(Plug-in)结构 - labats - LabATSS


因此,目前使用面向对象技术开发完解决方案后,代码发布应用是一个非常头疼的问题,特别是又涉及到扩展性问题的时候,目前我们采用的方案是以平面文件存储库发布可执行文件,结合源代码发布的混合式实现动态扩展的目的,该解决方案虽然部分解决了为用户提供一个可执行文件的执行入口点,源代码发布也可以支持动态扩展,但是也相应的混合进入了二者的缺点,及丑陋的平面文件存储库显示效果繁重,源代码发布会引入抽象基类的重复性,并在以后的程序开发中引起版本不一致而形成类型混乱。但是除此之外,尚无良策!

后继替代性解决方案有继续耐心等待LabVIEW NXG 的技术成熟,提供更好的技术基础,或者是采用混合式编程模式,部分底层测控代码直接迁移到.NET Framework技术栈上去,程序集(Assemble)的部署方式可以完美地支持二进制代码兼容及灵活动态扩展。 


最后我们可以简要的总结一下扩展插件结构的技术特点:

  • 通过Hardware Abstraction Layer (HAL)的引入使得我们将应用程序中MAL测量与实际的硬件测试驱动分离开,两者都依赖于抽象层。
  • HAL可以通过配置文件进行动态插拔切换(应用型号名称实例化具体驱动,设备程控地址配置化)。
  • 支持插件式的动态替换并且无需修改现有代码。
  • 目前发布面向对象程序可执行文件(EXE)解决方案尚无较为完美的方案。

参考文件

《敏捷技能修炼——敏捷软件开发与设计的最佳实践》,AlanShalloway, Scott Bain,Ken Pugh,Amir Kolsky, 郑立,邹骏,黄灵,机械工业出版社,2012年

  评论这张
 
阅读(70)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018