labview高级编程与虚拟仪器工程应用 代码_LabVIEW面向对象编程:设计背后的决策(翻译)(1)...

这是一篇讲解LabVIEW在开发实现支持面向对象编程内部语言机制的时候,NI核心语言研发团队(R&D)人员所做设计的背后决策,属于LabVIEW面向对象编程的高阶内容。原文较长,特分为三个系列文章进行翻译。
LabVIEW面向对象编程:设计背后的决策(翻译)(1)
LabVIEW面向对象编程:设计背后的决策(翻译)(2)
LabVIEW面向对象编程:设计背后的决策(翻译)(3)

原文连接,修订至LabVIEW 2009版本。

LabVIEW Object-Oriented Programming: The Decisions Behind the Design​www.ni.com
2152d4deb2990a053b145aa717d54e14.png

社区论坛的最早文章,发布于首次引入面向对象技术的LabVIEW 8.20版本。

面向对象的设计决策​forums.ni.com

LabVIEW:是一个设计工具吗?还是一种编程语言呢?实际上它是两者兼而有之,并且由于它是两者兼而有之,所以对于那些需要在没有计算机编程行家参与开发的情况下,用它来开发计算机程序的测试科学家和工程师们来说,是一个巨大的便利。当我们LabVIEW核心开发人员想要为其添加新特性的时候,我们必须考虑到我们的大多数用户并不是程序员。

在8.2版(2008年)中,我们引入了LabVIEW面向对象编程(LVOOP)。面向对象(OO)是一种充满抽象概念和技术词汇的编程范型。

对它的详细讲解要么需要对编程有深入了解,要么需要很长的学习曲线。

我们的目标是简化这种复杂性,使我们的用户能够广泛地应用OO的强大功能。这个决策选择的结果可能会让熟悉其他编程语言的OO支持者感到非常的惊讶。

本文章阐述了我们在创建LVOOP时所做的设计决策及其背后的推理。

本文章假设读者对LVOOP有一定的了解。在继续之前,大家可以先考虑查看LabVIEW帮助文档的相关部分和随机附带的示例程序以加深理解。

本文章已经更新为LabVIEW 2009版本。(翻译备注:十年前的版本了,但是其背后的知识概念并没有落伍。)

主要内容

  1. LVOOP的面向对象的高层设计
  2. LabVIEW中类的设计
  3. LabVIEW中类的方法设计
  4. 高级OO特性支持
  5. 结论
  6. 相关链接

1.LVOOP的面向对象的高层设计

为什么LabVIEW需要面向对象编程?

LabVIEW的目标是将计算机编程的能力交给那些没有接受过正式编程训练的工程师和科学家。我们希望构建出的LabVIEW ,让那些没有受过正式编程培训的用户感觉编程很直观。

作为几种最流行编程语言(Java,python)中的一种架构选择,面向对象编程已经证明了它优于过程编程。它鼓励代码各单元之间更干净的界面接口,更容易调试,并且对于大型编程团队来说,它可以更好地扩展。LabVIEW R&D团队希望我们的用户也能够获得这种能力。我们希望这种语言也能够实施一些通用软件的最佳实践。

面向对象编程比过程编程需要更多的预先设计。如果你写了一组只要使用几次的VIs,例如:也许是为了计算某个值、或者从DAQ卡中得到一个特定的测量值,那么构建一个类来包装那些VIs可能是略显多余。但是如果这些VIs形成了一个你计划维护几年的应用程序,那么面向对象可能是正确的选择。

我们希望LabVIEW拥有当下最新软件设计开发能力(面向对象),但是也不想让这些面向对象编程能力妨碍LabVIEW继续作为广为人知的便利的工程原型开发工具。

本文档中针对LabVIEW 2009更新的部分将在文本中以[LV2009]进行标注。

对于那些选择面向对象设计的人而言,我们需要连线和节点能自然演变成类和方法。

我们认为的“面向对象编程”到底意味着什么?

C++是一种面向对象的编程语言,Java和Smalltalk也是,具备面向对象编程能力的语言清单不胜枚举。这些语言都包含一个各自独特的特性集。

当我们决定将OO添加到LabVIEW时,我们必须决定这意味究竟着什么。C++模板是C++的本身特性还是OO的特性?操作符超载该如何处理?还有诸如Java的“Synchronized”关键字等等?

我们认为面向对象编程意味着两件事:封装和继承。

当我们决定要支持“什么”来称LabVIEW 为面向对象语言时,这是我们一直铭记在心的两大支柱。LabVIEW用户必须能够“封装”一个类数据类型——即定义一个数据块,例如一个簇,并告诉LabVIEW引擎运行时只允许在用户指定的函数中访问该数据块。

用户还必须能够“继承”一个新的类——即选择一个现有的类,以现有的类为起点创建一个新的类,并可以覆写父类的方法。

只关注这两个原则将有助于防止特征蔓延。

面向对象如何适应数据流?(老生畅谈的传值By-Value和传引用By-Reference之争)

LabVIEW使用数据流语法,程序框图中的节点对其输入进行操作,并且在大多数情况下,只对这些输入进行操作,而不会影响框图中其他连接上的值。

而每当连线分叉时,其值被复制。这些连线使用与数据流一致的“传值(By-Value)”语法。

例外情况是Refnum数据类型。Refnum是对内存中共享位置的引用,可以通过某种内建保护机制由多个节点操作。

LabVIEW中的Refnum类型包括队列、文件I/O、VI服务器类型等。当连线分叉时,共享内存并不重复。唯一的分叉复制的是让LabVIEW查找共享内存的地址参考数字。这些连线使用“传引用(By-Reference)”语法。

在开发LabVIEW类时,我们面临一个早期的决定:类连接应该是传值连线还是传引用连线。

参考C++,该语言有两种声明对象的方式:在堆栈上,或作为堆中的指针。当您将对象传递给一个函数或将其分配给另一个变量时,您必须始终知道您是通过值传递对象还是通过引用传递对象。您是刚刚复制了您的数据,还是正在与其他人共享您的数据?

另一方面,Java和C#只有引用语法。函数参数的变量赋值总是引用原始对象,要复制一个副本,需要显式地使用原始对象作为源重新创建一个新对象。

传值和传引用哪个对LabVIEW更为合适?在数据流语言中,使用传值语法意味着每条连线上的值独立于其他连线。这允许多个线程在代码中执行,而不必担心代码的某个部分会影响另一个部分中的值。

传引用语法打破了这种独立性。突然之间,用户需要负责跟踪一个引用被共享的次数,并确保代码的任何部分都不会与其他部分同时访问这个引用。用户必须理解受保护的部分、互斥对象和竞争条件。从好的方面来说,使用引用来构建特定的数据结构,特别是循环图或关系数据库,是比较简单的,而且这些通常很复杂的数据结构是人们使用OO的主要原因。

LabVIEW已经提供了连线拷贝分享数据的机制。尽管这些机制在某些应用条件下是不够用的,但它们确实存在良好,并且在每个LabVIEW版本中都得到了不断地改进。LabVIEW不需要其他方式来分享数据。它只需要一种隔离封装数据的方式,如果不能限制对数据的更改,就很难保证数据的完整一致性。为了支持封装,我们决定LabVIEW中的一个类基本上应该是一个不能被其所拥有的所有VIs分解的簇。当连线分叉时,对象将会被复制,这也是由LabVIEW编译器本身所决定的。

按值而不是按引用选择会影响所有其他设计决策。许多标准的OO设计模式都是基于一个对象,该对象能够指向并说“我只关心那边的那个对象”。LabVIEW有创建数据引用的机制——未初始化的移位寄存器、全局变量、单个元素队列——但是用户需要做更多的工作来利用这些机制,而不能直接使用内建的引用语法。

然而,这些其他机制已被证明足以构建许多复杂的数据结构。但是,任何传引用的解决方案都存在一个问题:这些结构与数据流不一致,因此它们无法从LabVIEW的最大优势之一:天生并行性中获益,遵循其他语言的设计模式会导致效率低下和奇怪的Bug,并且随着时间的推移,我们LabVIEW自己社区的设计模式出现了,这表明了传值语法的强大功能。

当人们第一次遇到LVOOP时,这个决定都是争论的焦点,但是LabVIEW的研发团队已经花了几年的时间来研究它,我们很有信心认为这是LabVIEW的正确选择。将来会考虑改进我们的传引用功能,但是可靠的传值实现对于任何与数据流范型一致的实际开发都是至关重要的。

在LabVIEW 2009中,我们引入了数据值引用(DVR)。这是一种全新的Refnum数据类型,可以作为对任何LabVIEW数据的引用,不管是普通整数、数组、簇还是LabVIEW对象。本文档后面将讨论这种新添加的语言元素。

OO词汇选择时考虑了哪些因素?

为一个概念选择的名字将会影响人们如何看待这个概念,以及他们学习这个概念难易程度。当我们将面向对象编程引入LabVIEW时,有很多关于引入多少“计算机科学”术语的讨论。

LabVIEW的目标是让没有接受过计算机科学培训的用户也能进行编程。我们的用户是从事测试和测量、工业控制和硬件设计的科学家和工程师。

LabVIEW的语法对于这些用户来说,首先是因为它与(电子电路的)线路示意图的高度相似性。我们也试图找到各种面向对象概念中便于理解的隐喻用语。

我们决定使用家族术语来表示继承层次:父类和子类、兄弟姐妹和表兄妹。这些概念用户已经在他们的词汇表中有了。当讲话者提到给定类的父类时,听众能够理解它们之间的关系,并且能够轻松地理解对话。我们本可以使用“超类”或“基类”这样的术语,但这些术语在人的头脑中并不能像家族术语那样建立起直接的联系。

本地化团队也喜欢这些易于翻译的术语。我们还明确了在用户界面和文档中绘制继承树的逻辑关系,即祖先在上面,后代在下面。在其他的OO编程语言中,开发人员在设计(绘图一致性上)会议上浪费了太多时间,他们没有意识到他们正在查看颠倒的树。我们希望鼓励LabVIEW开发者之间尽量保持一致性(从而提高沟通效率)。

对于访问范围(Scope)术语,我们决定最好遵循“私有”、“受保护的”和“公共的”行业标准。一些开发人员最初反对使用“受保护”这个词。私有数据和公共数据是直观的概念。“保护”这个词没有什么意义——保护什么?——人们很容易选择一个词来确定范围,比如“家庭”,这与我们选择的继承概念保持一致。

然而,“受保护的”这个术语在整个行业中都是一致使用的,无论使用何种语言,用户可能会在任何第三方帮助或教科书中看到这个术语。由于这个术语与LabVIEW中任何现有的概念都没有冲突,所以我们决定坚持使用标准术语。

当我们添加“Community”访问范围时,在大多数其他OO编程语言中没有类似的概念。在这种情况下,我们创造了自己的术语。如果你的继承树是“家庭”,那么你的朋友就是你的“社区”。我们认为这最清楚地解释了“社区”是如何与其他作用域相适应的,尽管说实话,我们中的一些技术人员对我们找不到一个以字母P开头的术语来与最初的三个作用域相适应感到失望。

“类”这个名词引发了最长时间的争论,“类”显然是“数据块和对数据分组操作的函数”的行业标准用法,这也是OO编程的基本思想。但是我们曾经讨论过另一个词是否对我们的用户更容易理解。LabVIEW已经有了Typedef的想法——一个基于现有类型定义新数据类型的控件VI。一个提议是避免使用关键字“Class”,而是讨论是否新增一种新的Typedef:对象Typedef。虽然对于第一次看到OO的LabVIEW用户来说,这在概念上更容易理解,但是考虑到我们最早的采用者可能是那些在其他语言中看到过OO的人。不使用“类”这个术语会让这些人感到困惑——没有类术语,一门语言怎么可能是OO的呢?所以,就像“受保护的“一样,我们决定遵循行业标准。我们在帮助文档中小心翼翼地将“LabVIEW类”与“VI服务器类”区分开来。

“虚拟”和“虚拟调度”的概念给LabVIEW提出了一个难题。这些术语也是行业标准。在C#、C++或Java中,虚函数是根据输入(“this”对象)的运行时数据类型调用不同版本的函数。LabVIEW函数被称为“虚拟仪器”。谈论“虚拟的虚拟仪器”是很尴尬的。此外,“虚拟”似乎从来就不是一个特别准确的术语——很难理解这些函数的“虚拟”的究竟是什么方面。

所以我们选择了“动态”和“动态分派”。这与静态分派的概念形成了鲜明的对比,后者是LabVIEW已经使用了几十年的SubVI调用。使用“Dynamic”和“Static”可以清楚地区分这两组VIs。“Static”在其他面向对象语言中有各种各样的含义,这给LabVIEW带来了问题;本文档后面将讨论这个术语。

关于其他术语还有其他一些较小的讨论。选择面向对象词汇表就如同构建一个操作访问界面一样。为了使面向对象概念易于使用,每个新加入的概念都必须受到挑战。我们完全不能假设某个特性的C++或Java名称就是LabVIEW中面向对象的正确名称。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值