第6章 LabVIEW面向对象程序设计

合集下载

第6讲 LabVIEW界面程序设计1

第6讲 LabVIEW界面程序设计1
• 程序框图的结构应该是越简单、越单一,越容易被人理解越好。
• 对于界面VI的程序框图而言,在循环事件结构外,应该只保留极 少量必不可少的节点,其他的代码统统移至循环事件结构内。初 始化和收尾可以被看做两个自定义事件,需要时发出事件,然后 跳至事件结构中相应的分支去处理即可。改进后的程序如下图所 示:
是不会产生值改变事件的。如果希望在程序中改变控件值的同时
也让它发出值改变事件,可以把值赋给控件的“值(信号)”属 性该数值控件会产生一个值改变事件。
• 用户在抛出“用户事件”时,需要给这个事件指定一个“事件名”。 循环事件结构捕获到这个事件后,跳入“用户事件”处理分支。在处 理这个事件之前,首先查看一下“事件名”,然后再根据“事件名” 对事件做不同的处理。
6.3 耗时代码的处理
• 界面程序不要把耗时较长的代码放在循环事件结构内,每个事件 处理分支内代码的执行时间尽量不要超过200ms,否则,当程序 停留在某一事件处理分支内长时间执行这段代码,程序无法立即 响应其他事件,用户可能误认为程序已崩溃或死锁。
• 下图是对初始化事件程序的改进方案。
• LabVIEW也自带实现了类似功能的VI,程序中可以直接使用自带VI。类似 VI在路径“[LabVIEW]\resource\importtools\Common\Event\Method”中。
• 下图为使用此VI的程序,”Create Event.vi”输入的参数相连的”Event in” 是“类”常量。
• 仅锁住用户界面是不够的,用户会对界面无反应产生疑惑。还有 其他方法,只是暂时忙于处理某事件,无 法处理用户的界面操作。最基本的做法就是把光标设为沙漏状, 这也是windows比较常见的处理方法。
• LabVIEW对光标操作的VI在“编程-对话框与用户界面光标” 中。

《面向对象程序设计》教案

《面向对象程序设计》教案

《面向对象程序设计》教案一、教案简介本教案旨在帮助学生掌握面向对象程序设计的基本概念、原理和方法,培养学生的编程能力和软件开发思维。

通过本课程的学习,学生将能够熟练运用面向对象的编程语言,如Java或C++,进行软件开发和设计。

二、教学目标1. 了解面向对象程序设计的基本概念,如类、对象、封装、继承和多态等。

2. 掌握面向对象程序设计的基本原则,如单一职责原则、开闭原则、里氏替换原则等。

3. 学会使用面向对象的编程语言进行程序设计和开发。

4. 培养学生的软件开发思维和团队协作能力。

三、教学内容1. 面向对象程序设计的基本概念1.1 类与对象1.2 封装1.3 继承1.4 多态2. 面向对象程序设计的基本原则2.1 单一职责原则2.2 开闭原则2.3 里氏替换原则2.4 接口隔离原则2.5 依赖倒置原则3. 面向对象的编程语言3.1 Java3.2 C++4. 面向对象的设计模式4.1 创建型模式4.2 结构型模式4.3 行为型模式四、教学方法1. 讲授法:讲解面向对象程序设计的基本概念、原理和编程方法。

2. 案例分析法:分析实际项目中的面向对象设计案例,让学生理解并掌握面向对象的设计思想。

3. 实践操作法:让学生通过编写代码,亲身体验面向对象程序设计的流程和方法。

4. 小组讨论法:分组进行讨论,培养学生的团队协作能力和解决问题的能力。

五、教学评价1. 课堂参与度:评估学生在课堂上的发言和提问情况,了解学生的学习兴趣和积极性。

2. 课后作业:布置相关的编程作业,检查学生对面向对象程序设计知识的掌握程度。

3. 项目实践:评估学生在团队项目中的表现,包括代码质量、设计思路和团队协作能力。

4. 期末考试:全面测试学生对面向对象程序设计知识的掌握情况。

六、教学资源1. 教材:推荐《Java面向对象程序设计》、《C++ Primer》等经典教材。

2. 在线资源:提供相关的在线教程、视频课程和编程练习平台,如慕课网、Coursera、LeetCode等。

LabVIEW中的面向对象编程技术

LabVIEW中的面向对象编程技术

LabVIEW中的面向对象编程技术在LabVIEW中的面向对象编程技术LabVIEW是一种基于图形化编程的工程软件。

它以图形化的方法创建程序,主要用于测试、测量和控制应用。

除了其强大的数据采集和处理能力外,LabVIEW还提供了面向对象编程(Object-Oriented Programming,简称OOP)技术,使得开发人员能够更加高效和灵活地设计和实现复杂的应用。

本文将介绍LabVIEW中的面向对象编程技术及其应用。

一、面向对象编程技术简介面向对象编程是一种软件开发方法,它以对象为基本单位,通过封装、继承和多态等特性,将程序的数据和对数据的操作进行有机的结合,使得程序的设计更加模块化、可复用和易于维护。

在LabVIEW中,面向对象编程技术被应用于虚拟仪器对象(Virtual Instrument Object,简称VI)的设计和开发。

VI是LabVIEW 程序的基本单位,通过面向对象的思想,可以将VI的功能、数据和界面封装成一个独立的对象,从而实现对其进行灵活的组合和重用。

二、LabVIEW中的面向对象编程1. 类和对象在LabVIEW中,类是面向对象编程的基本概念。

类定义了对象的属性和方法。

对象是类的实例,每个对象都有自己的属性值和方法。

2. 封装封装是面向对象编程的核心思想之一,它可以隐藏对象的实现细节,使得对象的使用者只需关注对象的接口。

在LabVIEW中,封装可以通过访问控制功能来实现。

例如,可以将某些属性设置为只读或只写,以限制对属性的访问权限。

此外,还可以使用属性节点来对属性进行封装,只允许通过特定方法对属性进行访问。

3. 继承继承是面向对象编程的另一个核心概念,它可以通过扩展已有的类来创建新的类,从而实现代码的重用和扩展。

在LabVIEW中,可以通过创建派生类来实现继承。

派生类继承了基类的属性和方法,并可以在此基础上进行扩展和修改。

通过继承,可以实现对现有功能的改进和功能的复用。

LabVIEW的面向对象编程指南

LabVIEW的面向对象编程指南

LabVIEW的面向对象编程指南LabVIEW是一款强大而灵活的图形化编程语言,广泛应用于数据采集、信号处理、测量与控制等领域。

而实现这些功能的关键就是面向对象编程(OOP)。

本文将深入探讨LabVIEW中的面向对象编程,为您提供一份指南,助您在LabVIEW中灵活运用面向对象编程技术。

1. 面向对象编程的基本概念面向对象编程是一种将现实世界的事物抽象成“对象”,并通过定义对象的属性和行为来实现系统开发的编程方法。

在LabVIEW中,对象是基于类(Class)的概念进行创建和使用的,每个类都有自己的数据和方法。

2. 类和对象的创建在LabVIEW中,类是创建对象的模板,是一种用户自定义的数据类型。

通过定义类的数据成员(属性)和方法(行为),可以实例化一个对象。

通过面向对象编程,可以封装数据和方法,实现代码的可重用性和扩展性。

3. 封装和继承封装是面向对象编程的核心概念之一。

它指的是将数据和方法封装在类内部,通过接口提供对外访问。

在LabVIEW中,可以使用“公共接口”来定义类的公共方法和属性,使得其他开发者可以通过对象调用这些方法和属性。

继承是指一个类可以继承另一个类的属性和方法,可以减少代码的重复编写,提高代码的复用性。

4. 多态性多态性是面向对象编程的另一个重要概念。

它可以通过定义一个通用的接口,让不同类的对象都可以实现该接口,并根据对象的不同实现调用不同的方法。

在LabVIEW中,可以使用动态调度方法,通过接口调用对象的方法,实现多态性的效果。

5. 事件驱动编程除了封装、继承和多态性,LabVIEW中的面向对象编程还支持事件驱动编程。

通过定义事件和事件处理程序,可以实现对象间的交互和通信。

当事件发生时,LabVIEW将自动调用相应的事件处理程序,对事件进行响应和处理,提高系统的灵活性和响应性。

6. 错误处理和调试在面向对象编程中,良好的错误处理和调试技术是不可或缺的。

LabVIEW提供了一系列的错误处理工具,如错误处理节点和自定义错误码等,可以帮助开发者在程序运行过程中及时捕获并处理错误。

精品课件-LabVIEW编程与项目开发实用教程-第6章 LabVIEW高级编程

精品课件-LabVIEW编程与项目开发实用教程-第6章 LabVIEW高级编程
图6-1 公式节点选板图6-2 添加输入输出图6-3 公式节点
第6章 LabVIEW高级编程
Байду номын сангаас2.输入公式
公式节点中代码的语法与C语言非常接近,但是只能实现基 本的逻辑流程和运算,不能对文件或设备进行操作或通信,且 代码中没有输入输出语句。公式节点中代码主要有以下几种语
句:
1)变量声明:float a; a+=b;
第6章 LabVIEW高级编程
图6-9 节点创建和添加输入输图出6-10 Matlab节点应用(左图 为LabVIEW波形图,右图为Matlab Plot图)
第6章 LabVIEW高级编程
6.2.2 MATLAB Script节点实例
【例6-3】Matlab节点创建复杂函数曲线
由于Matlab运算是基于 向量和矩阵的,因此程 序不需要增加LabVIEW 循环结构,直接通过右 键快捷菜单为输出变量 y选择1-D Array of Real类型,见图6-10。
y1 5sin(x / b) exp(-x / (m / b)) y2 cos(x / m) b
图6-8 程序框图和曲线
第6章 LabVIEW高级编程
6.2 MATLAB脚本节点
LabVIEW中的公式节点可以实现一些基本的数学运算,如果 涉及到比较复杂的数学运算,则可以调用Matlab的脚本文件( m文件)来实现。
第6章 LabVIEW高级编程
第6章 LabVIEW高级编程
6.2.1 MATLAB Script节点
Matlab节点位于 函数→数学→公式与脚本 脚本 子选板 内,添加Matlab节点的方式和前面章节中添加公式节点的方式 类似,见图6-9。
向Matlab脚本节点输入Matlab文件的方法有两种: 一种是直接在框内写入文件代码; 一种是在Matlab节点的边框上单击鼠标右键,在弹出的快 捷菜单中选择 导入 选项,在弹出的对话框中选择待输入的 Matlab脚本文件。 Matlab节点输入/输出变量的添加和公式节点类似,分别在 快捷菜单中选择 添加输入/添加输出 选项实现。和公式节点 一样,用户可以为Matlab脚本节点的每个输入/输出变量添加

《LabVIEW 程序设计教程》课件第6章 LabVIEW高级编程

《LabVIEW 程序设计教程》课件第6章 LabVIEW高级编程
一个前面板控件创建多个局部变量,其中一些是写模式,另一些是 读模式。在这种情况下要注意访问各个局部变量的顺序,以免程序出现 读写异常。一般可以用顺序结构,或通过连线关系人为地建立数据的依 从关系。
第6章 LabVIEW高级编程
【例6-4】滑动杆控制温度。
程序一开始运行,滑动杆的初始值就记录在数字显示控件“初始值” 内,滑动“滑动条”改变温度,如果温度超过上限30时,程序“超高”会亮 起,弹出对话框并结束程序。本例中,在两个地方使用了滑动杆控件的 局部变量,且为读属性。
第6章 LabVIEW高级编程
6.3.1 局部变量
1.局部变量创建与编辑
(1)鼠标右键单击一个前面 板中已有的对象,从弹出的快 捷菜单中选择 创建局部变 量 选项,便可创建为该对象 一个局部变量,如图6-11左。
(2)通过函数模板建立局部 变量。如图6-11右所示,选择 结构 局部变量 并将其拖放 到程序框图上。此时局部变量 的图标为 ,在图标上单击右 键弹出快捷菜单,选择 选择 项 数值。
第6章 LabVIEW高级编程
1.全局变量创建
建立全局变量也有两种方法,但比局部变量复杂。 (1)通过函数模板的结构子模板创建
在 函数结构 选板中选择全局变量节点,放置在后面板,此 时图标为
在图标上右键单击选择 打开前面板 或双击,打开全局变量程 序的前面板,在前面板上按照需要的数据类型加入控件,然后将 此程序关闭并保存为一个独立的文件;
第6章 LabVIEW高级编程
6.3.2 全局变量
局部变量与前面板上已有的某一个控件相联系,用于在一个程 序的不同位置访问同一个控件,实现一个程序内的传递数据。
全局变量用于不同的程序之间的数据传递,这些程序可以是并 行的,也可以是不便于通过接口传递数据的主程序和子程序。全 局变量的控件是独立的,它需要一个特殊的程序作为自己的容器 。因此可以说全局变量是一个内置的G语言对象。

LabVIEW面向对象编程技术

LabVIEW面向对象编程技术

-1$#’34 继承方式下 ! 基类的公有成员和保护成员在派
生类中为私有类型 " 但是 &’()*+, 中只有 -.(/$0 继 承方式 ! 只要存在继承关 系 ! 那 么 必 定 是 -.(/$0 继 承 方式 " 这是因为 &’()*+, 的开发者认为在实际编程 工作中 ! 保护继承与私有继 承的使用是极少的 ! 它们 只在技术理论上有意义 " &= $ 多重继承
收稿日期 "#--./!#/#修稿日期 "#--0/-1/-#
图 < 创建一个汽车类对象
在 #$%&’() 中既没有构造函数 " 也没有析构函 数的概念 & #$%&’() 定义类时 " 类中的用于定义数据 的控件 " 如图 9 中的 A3,.4.%-05;B,0 中的前面板中各 种数据的默认值就是数据的初始化 & 如果不采用默认
&’()*+, 中使用 . 静态 &B3’3$0 $/ 这个术语来描述
的 方 法 ! 跟 % // 中 描 述 的 . 静 态 / 含 义 完 全 不 同 -
&’()*+, 认为一个静态方法 &B3’3$0 C43D25 $ 就是一个
简单的子 #$&B.(#$$ 的调用 -
现 代 计 算 机 ! 总 第 二 八 一 期 "
%// 允许多重继承 ! 即分别从类 > 和类 ? 继承得
到类 %! 类 % 代表了类 > 和类 ? 的合成 ! 其同时具有 两个类的特征 " 而 &’()*+, !@< 中没有类似多重继承 的机制 !&’()*+, 的开发者认为在 &’()*+, 中 使 用 多重继承所能解决的问题和它所带来的问题一样多 ! 因此没有计划在以后的版本中推出该功能8A9" &" $ 实现对私有数据继承的方法

LabVIEW面向对象高级编程

LabVIEW面向对象高级编程

LabVOOP Design Patterns (version 1.0) Stephen Mercer, LabVIEW R&D, National InstrumentsTable of ContentsIntroductionThe PatternsSingletonFactoryHierarchy CompositionDelegationAggregationSpecificationChannelingVisitorConclusionIntroductionWhen talking about computer programming, a design pattern is a standard correct way to organize your code. When trying to achieve some particular result, you look to the standard design patterns first to see if a solution already exists. This sounds a lot like an algorithm. An algorithm is a specific sequence of steps to take to calculate some result from a set of data. Generally algorithms can be written once in any given programming language and then reused over and over again. Design patterns are rewritten over and over again. For example, in house cleaning, consider this algorithm for vacuuming a carpet: “Start in one corner, walk horizontally across the floor, then move to the side and continue making adjacent parallel stripes until the whole floor is vacuumed.” Compare this with the design pattern for cleaning a room: “Start cleaning at the ceiling and generally work your way down so that dirt and dust from above settle on the still unclean areas below.” Design patterns are less specific than algorithms. You use the patterns as a starting point when writing the specific algorithm.Every language develops its own design patterns. LabVIEW has patterns such as “Consumer/Producer Loops” or “Queued State Machine.” These are not particular VIs. Many VIs are implementations of queued state machines. When a LabVIEW programmer describes a problem, another programmer may answer back, “Oh. You need a queued state machine to solve that problem.” Starting in LabVIEW 7.0, LabVIEW has had VI Templates for many LabVIEW design patterns available through the File>>New… dialog. With the release of LabVIEW Object-Oriented Programming, we need to find the new patterns that arise when objects mix with dataflow.The seminal text on design patterns appeared in 1995: Design Patterns by Gamma, Helm, Johnson and Vlissides. This text is colloquially known as “the Gang of Four book.” This text focused on object-oriented design patterns, specifically those that could be implemented using C++. Many of those patterns are predicated on a by-reference model for objects. As such they apply very well to classes made with the GOOP Toolkit (or any of the several other GOOP implementations for LabVIEW). LabVIEW classes, added in LV8.2, use by-value syntax in order to be dataflow safe. This means that the known patterns of object-oriented programming must be adapted, and new patterns must be identified. This document describes the LabVOOP-specific patterns I have identified thus far.This document is not on NI’s DevZone as I do not wish to give an official imprimatur to these yet. The descriptions and methods of implementation may not be as optimal. I am posting these as a common LabVIEW user, not as a member of LabVIEW’s R&D team.– Stephen Mercer Reference:Design Patterns Gamma, Erich, et al. 1995.Addison Wesley Longman, Inc.Singleton Pattern(adapted from Gang of Four’s Singleton pattern)IntentGuarantee that a given class has only a single instance in memory, that no second instance can ever be created, and that all method calls refer to this single instance.MotivationWhen you create a class, sometimes it is advantageous to guarantee that a program always refers to the same global instance of the class. Perhaps the class represents a database. It would be unfortunate if some section of code accidentally instantiated its own database and thus failed to update the global database. Creating a global means all VIs can access the data. But it does not mean that all VIs will access the global. This pattern describes a framework of classes that guarantee that single instance of data.ImplementationSee/SingletonPattern.zip(An example of this pattern shipped with LV8.2, but that example is flawed, a problem I did not realize before we released: <labview>\examples\lvoop\SingletonPattern\Design Pattern.lvproj )In this implementation, we seek to guarantee a single instance of Data.lvclass. We achieve this by putting Data.lvclass into an owning library, Singleton.lvlib, and making the class private. Now no VI outside the class can ever drop the class as a control, constant or indicator, so we guarantee that all operations are limited to this library. Callers can use Singleton.lvlib:Checkout.vi to get the current value of the data, modify it using any of the operations defined by Singleton.lvlib and then set the new value with Singleton.lvlib:Checkin.vi. The public functions are the same functions that would normally be on the class itself. They are moved to the library so that the functionality is exposed without allowing the class itself to be dropped. Checkin.vi and Checkout.vi use a single-element queue to guarantee only one copy in memory at a time. While the element is checked out to be modified by some routine, no other operation can proceed, thus guaranteeing serial access to the data. Editorial CommentsI do not like the implementation that shipped with LV8.2. In the time since LV8.2 released, I have found better ideas. This “post-release discovery” is one reason why more design patterns are not included with the shipping product. LabVOOP is too new, and many of the patterns identified during development may be found faulty when exposed to a wider audience (i.e. real customers). So I’m making this implementation available.The only hole in the above solution that I can find is VI Server. VI Server could get a reference to the Front Panel controls of Singleton’s member VIs and use the Value property to effectively manipulate a different instance of the class than the one in the queue. Would using Subroutine Priority prevent VI Server access? I think so, but that seems like a pretty odd way to fix these VIs. The fix may not be that necessary – I doubt that many people are going to attempt such a hack on the class. Anyone trying it is already aware that they’re working against the design of the class and may break components that depend upon the singleton nature.Factory Pattern(adapted from Gang of Four’s Factory pattern)IntentProvide a way to initialize the value on a parent wire with data from many different child classes based on some input value, such as a selector ring value, enum, or string input. This may include dynamically loading new child classes into memory. Ideally new child classes can be created and used without editing the framework. MotivationData comes from many sources – user interface, network connection, hardware – in a raw form. This data frequently comes in types, and the data is to be handled generically but each type has a specific behavior at the core of the handling. Such a problem cries out for the use of classes and dynamic dispatching. We want to write an algorithm around some common parent type and then let dynamic dispatching choose the correct subVI implementation for the parts of the algorithm that are type specific. The hard part is in initializing the right class from the input data.ImplementationAn example of this pattern was made available by Christina Rogers in her refactoring of the Getting Started Window in the Init From XML methods. Information about this example is available here:/2006/08/object-oriented-getting-started-window.htmlThe general idea is this: Use your data to identify which class you are interested and get the name and/or path to that class’ file. Then use the Application Properties to get access to that class. Suppose we name our parent class Generic Plugin.lvclass. All of our data will be wrapped by specific child types of Generic Plugin. After we have chosen the path to the child class, we proceed as follows:1.Open reference to the .lvclass file on disk. This returns a LVClassLibrary refnum.2.Get the default instance of the class.3.Cast the LabVIEW Object that gets returned to your plug-in data type.From there you would wire the chosen class instance to an Init method of the class which would take your data as an input. The advantage of this system is that the child class is only loaded into memory if someone actually wants to instantiate that child. If you have a great many possible types of data, this can save on memory and load time for your application. The name of this pattern comes from the fact that a single VI serves as a factory to produce all the myriad child types.Editorial CommentsThis implementation does not work in the run time engine because the LVClass refnum does not exist in the runtime engine. Without this, a much less elegant solution must be used. Instead of identifying the path to the class, use your data to pick an enum value, and wire that enum to a case structure. Each frame of the case structure should have a constant of the specific child class. This alternative implementation does not do dynamic loading and requires that all child classes be known and in memory when the VI loads. It further means editing the factory each time a new child class is created.Hierarchy Composition Pattern(adapted from Gang of Four’s Composite pattern)IntentTo represent a single object as a tree of smaller instances of that same object type. Useful for images (an image is made of a set of subimages), file systems (directory contains both files and other directories) and other systems where there is a common aspect to both the whole object and its parts.Motivation“Composition” refers simply to using one class as member data of another class. One class is thus “composed” of another class. The Hierarchy Composition pattern is specifically for times when you are making a class that is going to be composed of smaller instances of itself.ImplementationAn example of this pattern shipped with LV8.2. See<labview>\examples\lvoop\Graphics\Graphics.lvprojThis example includes a class hierarchy for Graphic.lvclass, as shown in the image.A graphic is simply something that can be drawn. Graphic defines a method Draw.vi,which can be overridden by children. There are three children of Graphic. The first twoare straightforward implementations: Point.lvclass and Line.lvclass. Each of these twohave coordinate data as their member data, and implement Draw.vi accordingly. Thethird class, however, is Collection.lvclass. Collection has as its private data an array ofGraphics. That is, Collection, which is itself a Graphic, contains other Graphics. It’simplementation of Draw is to loop over that array and call Draw for each containedelement. The demo shows how a Collection graphic can be built up from individualpoints and lines.You could continue this, adding a Collection inside a Collection, nesting them to createmore complex Graphics.The difficulty arises when trying to call Draw for a Collection that contains another Collection. This is a recursive call to Collection.lvclass:Draw.vi. LabVIEW does not support recursion and will abort the VI when the recursion is attempted at runtime. There are ways around this barrier. Exploration of the various pros and cons of the workarounds has been proceeding on the LAVA Forums:/index.php?showtopic=3830Delegation PatternIntentTo have two independent classes share common functionality without putting that functionality into a common parent class.MotivationGood object-oriented design requires each class to focus on its assigned task. A class shouldn’t have member VIs unrelated to its task. If you have two classes that have some shared functionality, the usual solution is to create a parent class that both of them inherit from. Sometimes, however, you already have a class hierarchy created and a new feature comes along. The new functionality needs to be added to two existing classes that either do not have a common ancestor or do have a common ancestor but that ancestor is several generations up and not every descendent of that ancestor should have the new functionality. In some languages you might try multiple inheritance. But even in languages that support multiple inheritance, delegation is generally a better solution.This pattern applies best when you have a dynamic VI inherited from some ancestor and two descendent classes want to override that dynamic VI with exactly the same implementation. Delegation helps you avoid writing the implementation twice, once for each of the two classes.ImplementationAn example of this pattern was made available by Christina Rogers in her refactoring of the Getting Started Window in creation of her Project Wizard class. Information about this example is available here:/2006/08/object-oriented-getting-started-window.htmlThe general idea is this: Create a third class that has the new functionality. The new class is frequently something like “Function Helper” or “Function Assistant,” where “Function” is whatever functionality is to be delegated. Give that class all the data fields necessary to carry out the new functionality. Then add that third class as a data member to the two classes that need to share the functionality.The two descendent classes override the ancestor’s dynamic VI. But they only put in a bit of code necessary to call the exact same method on their data member of the helper class. The actual work is entirely in that method of the helper class. Now there is only a single instance of the code, which makes bug fixing easier. The two descendent classes have delegated the work to a third class. Thus the name of this pattern.Editorial CommentsThis pattern is not listed explicitly in the Gang of Four text. The idea occurs as an aspect of several other patterns. I think it is useful enough to warrant specific attention.IntentTo treat an array of objects as a single object.MotivationAn array nicely collects data together into an indexable list. But there are many primitives that operate on an array: Build Array, Remove From Array, etc. There are times when you want an array to guarantee certain properties, such as:•an array that guarantees that no duplicates are ever inserted•an array that is always sorted•an array that doesn’t allow removing elementsThis pattern creates a class that lets you treat an array of another class as a single object.ImplementationNo examples of this pattern are publicly available yet. Here is a summary of the pattern:Suppose you have Data.lvclass. Now you create ArrayOfData.lvclass. In ArrayOfData’s private data cluster, you add an array of Data. The only operations that can be performed on this array are those that you add to ArrayOfData. To guarantee no duplicates, write Insert Element.vi such that it checks the array for existing values before doing the insert. If you need to make sure the data stays sorted, you can write Insert Element.vi such that it inserts data at the correct position. Whatever functionality you supply – or leave out, as in the case of an array that does not allow removing elements – defines what can happen to the array.The new class represents an aggregation of many instances of another class. Thus the name of this pattern. Editorial CommentThis is an easy pattern to understand, and it is easy to think of the implementation on your own. Not all the patterns are complex systems. Sometimes pointing out the obvious is useful. When planning a new application, you may look at a list of patterns to consider what the best design would be. Having these so-called “obvious” patterns in the list helps remind you that you ought to use them. Because as easy as this pattern is, it is easier just to have a raw array running around on your diagram (you don’t have to write a bunch of accessor VIs to duplicate the functionality already found on certain primitives). There are times when you’ll choose to do that. But as your code gets more complicated over time, you may find yourself wishing that you had wrapped the array up so that you could guarantee certain characteristics.IntentTo have different functionality for a class depending upon some value of the class without updating case structures throughout your VI hierarchy when you add another value.MotivationYour data has some field – perhaps an enum, perhaps a string, perhaps something more complex – and you have a case structure that cases out on that field to decide which of several actions to perform. The data in this field is constant (once you have initialized the class this field never changes). When you find yourself creating a lot of these case structures, or, worse, updating a lot of these structures to add a new case, you should remember this pattern.ImplementationExamples of this pattern occur in just about every shipping example.If the data is constant from the time the class is initialized onward, then you should strongly consider creating a set of child classes. The data in that field is unnecessary data – stop hauling it around the diagram. A class knows its data type. If you need that value, you can get it from some static VI on the class that just returns a constant. Further, those case structures can now be replaced with dynamic subVI calls. For every distinct case structure, create a new dynamic VI on the parent class and put the code that used to be in each frame of the case structure in one of the children’s override VIs. Now when you add a new case, there are no case structures to update. So instead of one monolith class with an enum type, you now have many more specific classes. Thus the name of this pattern.This pattern is frequently used in conjunction with the Factory pattern.Editorial CommentLike the Aggregation pattern, this is an “obvious” pattern. But it is easy to overlook the fact that a piece of data never changes. If data never changes, that data is effectively part of the data type. Clusters that carry around the name of their data or a string representing the source of the data cry out for application of this pattern. This pattern is basically the central use case for class inheritance and dynamic dispatching. It simplifies many very complex VIs and clusters into manageable chunks by giving an easy way to break up the functionality of the case structure across multiple VIs. This pattern is the first one that a new user of object-orientation should learn, and generally the first one to consider when refactoring existing applications.Channeling PatternIntentTo provide a guaranteed pre-processing/post-processing around some dynamic central functionality.MotivationYou have a class hierarchy. And you have some algorithm that you want to implement on the parent class. There is a core step of the algorithm that needs to be dynamic so that each child class can provide its own behavior. But it is unsafe to call that step directly – you want a class interface that guarantees the step is only called from the algorithm VI.ImplementationNo examples of this pattern are publicly available yet. Here is a summary of the pattern:The parent class has the VI that implements the algorithm. Make the algorithm VI a static VI (no dynamic inputs). That way the child classes cannot override the algorithm itself and thereby avoid calling the pre-processing/post-processing. Make the dynamic step of the algorithm a dynamic VI that the child classes can override and make the dynamic VI be protected in the parent class. This forces all the children to use protected scope for their override VIs. No VI outside the class hierarchy will be able to call the dynamic VIs directly. This pattern does not prevent child classes from calling the step on themselves or other child classes without going through the algorithm. It does make sure that all the VIs outside the class hierarchy always go through the algorithm VI.The name of this pattern refers to the control of the flow of data – the data is channeled through the static VI to get to the dynamic VIs.Editorial CommentA customer asked me why all member VIs in classes aren’t dynamic. The performance overhead of dynamic VIs is pretty small (and constant no matter how deep the class hierarchy or how many dynamic VIs there are on the class) such that it made sense to the customer to make all the VIs dynamic and only make static VIs if a performance problem actually arose. That would give maximum flexibility to the class. This pattern is one of several reasons not to make everything dynamic. If the algorithm itself were dynamic, child classes might decide to override the algorithm and skip the pre/post processing. This pattern is particularly useful for large programming teams where you might not know all the developers, or where child classes will be implemented by third parties. It lets the original author put compiler-enforceable guidelines into the code so that future programmers do not unwittingly write VIs that will create issues for the architecture.Visitor Pattern(adapted from Gang of Four’s Visitor pattern)IntentTo write a traversal algorithm of a set of data such that the traversal can be reused for many different operations.MotivationSuppose I have an array of integers. I need a function that will calculate the sum of those integers (ignore, for the sake of argument, the fact that there’s a primitive to do this). I drop a For loop and iterate over every value, adding each element to a running total in an uninitialized shift register. The value in the shift register when the loop finishes is my sum.Now suppose I want to find the product of those integers. I write the same For loop and shift register, only instead of the Add primitive, I use Multiply. Everything about these two VIs is exactly the same except for the core action. How can I avoid duplicating so much code?Dynamic dispatching does not immediately help in this case – I do not have any child types on any of the wires that I can dispatch on. I could make my traversal VI have a VI Reference input. Then, instead of calling a primitive, I could have a Call By Reference node. The VI that I pass in would have either the Add or Multiply primitive.This is helpful, but only works if my two VIs have exactly the same connector pane. What if I need other information, other parameters, to do the job in that Call By Reference node?ImplementationAn implementation of this pattern is available here:/LV2OO_Style_Global_v1.0.zipInstead of taking in a VI Reference, the traverse VI takes in an object of class Action. This is a class that you define. Create one child class of Action for each specific action you want to do during the traversal. Then instead of a Call By Reference node, call the Do Action.vi method. This will dynamically dispatch to the correct implementation. The Action object can have all sorts of data inside it that can augment the operation at hand. You can implement as many new Action children as you want without ever having to change your original traversal framework.The traversal VI can get very complicated, far beyond the simple For loop over an array that I mention here. As the traversal walks over a data set, the Action object “visits” each piece of data and updates itself. Thus the name of this pattern. Your visitor can collect a summary of information about the pieces of data (such as the sum and product calculations), or it might search for a particular value, or it might even modify the data as it visits (divide each value in the array by 2). The traversal works just as well in all of these cases.Editorial CommentI am tired of writing LV2-style globals. These globals are great – very dataflow efficient, very easy to understand. But you have to duplicate the VI every time you want to support a different data type. I figured there had to be a better way. I’ve been thinking about this implementation for a while. It may not be optimal, but I think it is an excellent starting point. Imagine… the possibility of never writing another LV2-style global VI ever again, because you could just reuse one and give it the particular action that you want. A whole new flavor of über-geek nirvana!ConclusionThose are the design patterns thus far. I hope to update the list as time goes by, both with more patterns and with better examples for the existing patterns. Pay attention to the code you write – when you find yourself following the same routine over and over, try giving a name to the pattern. See if you can clearly identify when it is useful and how best to do it.Exploration of these patterns helps us design better code. Using the patterns is using the learning of previous developers who have already found good solutions. In studying the patterns, we can learn what good code “feels” like, and we are then more aware when we create an unmaintainable hack in our own programs.When we follow the standard designs it helps others looking at our code understand what they’re looking at. If a programmer knows the general pattern being used, he or she can ignore the framework and focus on the non-standard pieces. Those are the points are where the program is doing its real work. It is akin to looking at a painting in a museum – the painting is the interesting part. The picture frame and the wall are just there to hold up the art. If the frame or wall are too decorative, they pull the focus.I do not talk about any anti-patterns in this document. Anti-patterns are common attempts that look like good ideas but have some generally subtle problem that will arise late in development. Some anti-patterns in other languages are sufficiently detectable that a compiler could even be taught to recognize them and report an error. Perhaps these exist in LabVIEW. We should be cataloguing these as well.For those who chose object designs,we want the world of wire and nodeto morph naturallyinto a world of class and method.– LabVOOP。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。


8
6.2LabVIEW与面向对象程序设计
多态
多态性表现有两种,即编译时的多态性和运行时的多态性 。编译时的多态性是用函数的重载来实现的,运行时的 多态性是用虚函数来实现的,而这两种方式在LabVIEW 的类中都没有实现。 首先,LabVIEW类不支持重载,但这种多态性的思想在 LabVIEW的早期版本中就一直存在并发挥着重要作用, 主要表现为多态的函数、VI和单位; 其次,对于虚函数而言,“虚拟”和“虚拟分配”的概 念在LabVIEW中也面临一些问题,LabVIEW面向对象编程 选择了“动态”和“动态分配”来代替这两个术语。

5
6.2LabVIEW与面向对象程序设计
LabVIEW引入面向对象编程时的术语
LabVIEW依然使用家族关系术语:父与子、兄弟与堂兄 弟等,这些都是用户已经熟悉的术语,当提到某个类的 父类时,都可以理解这两个类之间的关系; LabVIEW类成员的限定性术语:依然采用“私有的”、 “共有的”和“受保护的”等词汇。
更改后的 继承关系

15
6.3LabVIEW对象基本实现
创建方法
在类名称上右击,选择需要创建VI的类型:普通成员VI、动态 成员VI或重写VI(Override VI)。

16
6.3LabVIEW对象基本实现
LabVIEW面向对象程序设计
Intelligent Electronics Institute Huazhong University of Science & Technology
目录
面向对象 LabVIEW与面向对象程序设计
LabVIEW对象基本实现
LabVIEW对象高级技巧
实例介绍
提示与建议
在面向对象程序设计中,继承表达的是类之间的关系,这种关 系使得一个类可以继承另一类的属性和方法,从而提供了通过 现有的类创建新类的方法,也提高了软件复用的程度; 多态是面向对象程序设计的重要特性之一,是指不同的对象收 到相同的消息时产生不同的操作行为,或者说同一个消息可以 根据发送消息的对象的不同而采用多种不同的操作行为。
Байду номын сангаас
27
6.4LabVIEW对象高级技巧
在类实现时,LabVIEW需要为一个类分配数据空间

28
6.4LabVIEW对象高级技巧
动态分配
动态分配是LabVIEW的一个特色,一个看似单个VI调用 的节点在运行时实际上调用的是一组VI中的某个,这取 决于运行时动态分配输入端连线上的值; 每一个在连线上传递的对象都含有指向其类信息的指针 ,这个类信息包含了一个“动态分配表”,它是一个VI 引用表; 每个类首先复制了其父类的动态分配表,同时它用自身 重写的VI方法替换父类中对应的方法,然后将没有重写 的父类动态分配VI添加到表中。
私有数 据成员

12
6.3LabVIEW对象基本实现
设置继承
在LabVIEW中,通过“继承”可在现有类的基础上创建 一个新类; 当一个新类被设置为继承另一个LabVIEW类时,这个新 类就可以使用它所继承的类中“公共”及“保护”型的 成员VI; 在LabVIEW中,所有的类都默认继承LabVIEW Object的 基本类。

19
6.3LabVIEW对象基本实现
右击“保研生”类,选择“新建”下拉列中的“用于重 写的VI”,会出现一个提示框用于选择需要重写的动态 VI。我们选择“大四学生”类下的“获取成绩.vi”, LabVIEW会自动生成一个“保研生”类下的“获取成绩 .vi”。

6
6.2LabVIEW与面向对象程序设计
继承
LabVIEW在实现继承特性时坚持这样一条原则:LabVIEW 用户能够实现类的继承,可以选择一个已有类作为父类 ,创建一个子类,并且可以覆盖父类中的方法; LabVIEW提供了(Object)类,作为所有LabVIEW类的祖 先; LabVIEW目前只支持公共继承,而不支持私有继承和多 继承。
使用类获取大一成绩程序框图

25
6.4LabVIEW对象高级技巧
构造函数与析构函数
在一般的面向对象程序设计语言中,对象在创建和销毁 时会自动调用两个函数:构造函数和析构函数;
构造函数的作用是在对象被创建时利用特定的值构造对 象,将对象初始化为一个特定的状态,使对象具有自己 的特征; 析构函数则用来完成对象被删除前的一些清理工作,析 构函数调用完成之后,对象将被销毁,相应的内存空间 也被释放;
在LabVIEW的面向对象编程中,构造和析构是隐含的, 不需要用户编写或调用。

26
6.4LabVIEW对象高级技巧
内存分布
在LabVIEW中,类的高效存储是一个挑战性的问题。 一个类的数据包括从父类继承来的数据簇和自身的私有 数据簇。

21
6.3LabVIEW对象基本实现
动态分派程序
在编写程序时,动态成员VI在程序背面板上就像一般的子 VI一样,不过当运行时,输入端口传递进来的数据就决 定了调用哪个类中的成员VI。

22
6.3LabVIEW对象基本实现
访问范围设置
LabVIEW类只包含私有成员数据,但可以为类的成员VI指 定访问范围。成员VI的访问范围选项包含如下设置: a) 公共(Public),任何VI都可以调用该成员VI; b) 保护(Protected),仅该成员VI所在类及其子类中的 VI可以调用该成员VI,在项目浏览器窗口中受保护的成 员VI图标中有一个暗黄色的钥匙符号; c) 私有(Private),仅该成员VI所在类中的VI可以调用 该成员VI,在项目浏览器窗口中私有型的成员VI图标中 有一个红色的钥匙符号。
“保研生”类 中获取成绩的 程序框图

20
6.3LabVIEW对象基本实现
输入或输出接线端
对于动态VI,右键单击连线板上的输入或输出接线端,会发现其 连接为动态分配模式。
“保研生”类 中获取成绩的 输入端口

习题

2
6.1面向对象
对象与类的概念
对象是系统中用来描述客观事物的一个实体,是构成系 统的基本单位,由属性和对这些属性进行的操作等构成; 类是对象的抽象及描述,是具有共同属性和操作的多个 对象的统一描述体,类也是对象,是一种集合对象;
在类的描述中,每个类要有一个名字,要表示一组对象 的共同特征,还必须给出一个生成对象的实例的具体方法;

10
6.3LabVIEW对象基本实现
私有数据控件示例
类库文件中的 私有数据控件

11
6.3LabVIEW对象基本实现
编辑私有数据成员
在项目浏览器窗口双击类的私有数据控件,可以对类中的数据成 员进行编辑,将需要的控件放置到该类的定义私有数据控件中 ,作为类私有数据簇中的成员。

23
6.3LabVIEW对象基本实现
在类上右击,选择属性后可以设置一个VI的访问范围

24
6.3LabVIEW对象基本实现
使用类
在创建LabVIEW类的实例时,用户可直接将这个类的类库文件 (.lvclass)作为控件或常量放置在相应程序的前面板或程序 框图中; 在LabVIEW类中,所有的私有数据被定义为一个簇,通过在成 员VI的程序框图中调用函数来访问和操作这些数据; 对LabVIEW类进行捆绑或解除捆绑时,节点上仅显示当前类私 有数据的接线端,而不显示从父类继承的数据的接线端。
对象的属性和方法是对象定义的组成要素,它们统称为 对象的特征。

4
6.1面向对象
面向对象中的三要素:
封装 继承
多态
在面向对象的程序设计中,封装就是把相关的数据和代码结合 成一个有机的整体,形成数据和操作代码的封装体,对外只提 供一个可以控制的接口,内部大部分的实现细节对外隐蔽,达 到对数据访问权的合理控制;
类中的每个对象都是该类的对象实例,系统运行时通过 类定义属性初始化可以生成该类的对象实例。

3
6.1面向对象
属性与方法的概念
对象是属性及方法的封装体; 对象的属性是指描述对象的数据,这些数据可以是系统 或用户定义的数据类型,也可以是一个对象的数据类型 ; 对象的方法是指定义在对象属性上的一组操作的集合; 方法是为响应消息而完成的算法,表示对象内部实现的 细节,对象方法集合体现了对象的行为能力;
新建静态成员VI
新建静态成员VI后,会打开一个空面板的VI, 用户可以根据应用需要添加程序代码;
静态方法只有单个VI,在子类中无法创建与父 类静态成员VI相同名称的成员VI。

17
6.3LabVIEW对象基本实现
新建动态成员VI
新建动态成员VI后,会打开一个含有部分代码的VI,其中包括 错误输入簇、错误输出簇、用于错误处理的条件结构,以及输 入LabVIEW类和输出LabVIEW类; 动态成员VI主要出现在具有继承关系的LabVIEW类中,只有当 子类需要继承并重写父类中的某些VI时,这些VI才有必要设置 为动态成员VI。

7
6.2LabVIEW与面向对象程序设计
封装
LabVIEW实现了类的封装,但对封装特征进行了选择; LabVIEW类只包含对私有数据的支持,不提供公共数据 和受保护的数据两种属性; LabVIEW类中的方法,不仅可以是私有的,还可以是公 共的或受保护的。

9
6.3LabVIEW对象基本实现
创建类
通过菜单“File→New→Class”或者在项目浏览器的右 键快捷菜单中选择“New→Class”项,都可以创建 LabVIEW类; 创建类时,LabVIEW将创建一个新的类库文件( .lvclass),该文件可以记录类的私有数据控件( Private Data Control)和所有被创建的成员VI的信息 ,包括VI列表及VI的属性等; 类的数据被定义在私有数据控件中,私有数据控件是一 个数据簇,与类库文件是一一对应的,并保存在类库文 件中,私有数据控件的名称以“.ctl”作为扩展名。
相关文档
最新文档