资源预览内容
第1页 / 共22页
第2页 / 共22页
第3页 / 共22页
第4页 / 共22页
第5页 / 共22页
第6页 / 共22页
第7页 / 共22页
第8页 / 共22页
第9页 / 共22页
第10页 / 共22页
亲,该文档总共22页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
LVOOP之适配器模式 12/25/20090 Comment(s) 适配器是常见的硬件概念,比如我们常用的USB转RS232适配器。我们之所以采用适配器,主要是由于以下原因:一、原有硬件设备已经存在,新的连接设备不存在和旧设备一致的接口。二、新的设备需要连接很多不同接口的设备,需要构建一个统一的接口。 OOP适配器模式借用了硬件适配器的概念。软件的升级换代是非常常见的,对于已经成功运行的软件系统,我们在设计新的软件系统时,不可能完全放弃原有的软 件系统。但是经常遇到的情况是原有的软件系统和新的软件系统具有不同的理念,在考虑到扩展性的同时,必须兼容原有的软件系统,此时适配器模式是我们首选的设计模式。我们看一下适配器模式的定义: 适配器模式将一个类的接口转换成客户希望的另外一个类的接口。适配器模式使原本不兼容而不能一起工作的类可以一起工作。 适配器模式并非特别的技术,其实质是在新的类中借用(翻译)原有类的动作和行为。在面向对象的编程中,当然是两个类之间的关系。对于LV来说,由于早期不存在LVOOP,因此适配器很少针对两个类,但是适配器模式的设计思想完全可以推广到面向过程和面向对象的混合编程中。下面我们通过一个绘图类说明如何使用适配器模式。 我们的目的是建立一套通用绘图程序类,包括点、线、圆等等,从图形的角度看,无论是点还是圆形,都存在很多共同点,比如绘图颜色、画笔等等,因此建立一个 形状的类作为基类是非常合适的,在基类的私有数据中存储公共特征,比如颜色和画笔,另外需要在基类中创建一个可重写的绘图函数,这样基类和继承的特殊形状 的子类都可以使用同一绘图函数,实现类的多态特性。 我们创建一个形状类作为基类,形状类的私有数据包括画笔和颜色,并分别创建了私有数据的读写属性,形状类中,我们创建了可重写的绘制形状方法。属性的程序框图非常简单,就不贴图了。看一下形状类中可重写绘制形状的程序框图。 在基类的绘图函数中,不执行任何实际绘图工作,具体绘图工作延迟到具体子类中实现。 我们知道,绘制一个圆需要圆的半径和圆心,其中圆心是一个点,因此我们创建一个点类,并将点类作为圆类的私有数据成员之一。 在绘制圆类中,我们创建了一个静态方法,用来设置圆心和半径,其实这完全可以通过属性实现。由于属性只能设置单一私有数据的值,而采用方法则不受此限制。 我们今天讨论的是适配器模式,假设在原来版本中已经存在类似的绘制圆的类,但是其属性和方法与我们新创建的不同,比如名称,参数顺序等等。由于原有类已经 应用于程序中,并在多处使用。如果直接使用新的绘制圆类,必然导致原有程序的多处修改,这不符合开放封闭原则。这种情况下,适配器方式就非常实用了。 为了说明适配器模式,我创建了一个Circle类,表示原来存在的绘制圆类,简单起见,直接封装了LV的绘制圆函数,未执行任何其他操作。 回过头来,我们看看如何在新建的绘制圆类中,通过适配器方式,调用原有的CIRCLE类,来实现绘制圆的操作。 上面的程序框图为绘制圆类中重写的绘制形状方法,在该方法中,建立一个原来的CIRCLE类的实例,并调用了CIRCLE中绘制圆的方法。 适配器模式是比较简单的,借助于适配器,可以充分利用原有结构。原有结构处于封闭状态,但是通过适配器后,改变了原有类的接口,这样就实现了开发的功能扩展。 适配器模式基本使用的是类的封装功能,对原有类进行进一步的封装,创建新的接口,使之融入到新的体系中。LVOOP之建造者模式 12/18/20090 Comment(s) 建造者模式是非常常用的设计模式,顾名思义,该模式主要一个对象。builder的意思是建造者或者建筑工人,想到建造者自然会想到楼房。楼房是千差万别 的,楼房的外形、层数、内部房间的数量、房间的装饰等等,但是对于建造者来说,抽象出来的建筑流程是确定的。建筑一座楼房,首先需要打桩、建立基础,然后 建立框架。建造者模式最为重要的是流程是不变的,每个流程实现的具体细节则是经常变化的。 建造者模式保证了流程不会变化,流程即不会增加、也不会遗漏或者产生流程次序错误,这是非常重要的。我们熟知的楼歪歪事件,官方的解释就是由于先建立楼房后,再建设停车场造成的,这是典型的建造次序错乱。 其实在编程实践中,建造者模式比比皆是。 比如文件操作,包括打开、读写文件和关闭三个步骤,无论是二进制文件、文本文件、TDMS 文件都必须遵循这个流程。其实、打开、读写、关闭并不仅限于文件,串口操作、GPIB等等,都遵循着同样的流程,不过是每个流程的实现细节不同。 任何人的成长过程也是一个典型的建造者模式,都包括婴儿阶段、少年儿童阶段、青年阶段、中年阶段和老年阶段。每个人在各自阶段成长的结果是各自不同的,但是整个成长过程肯定是确定不变的,不可能出现先老年、后儿童的情形。 我们看看建造模式的定义。Builder模式的缘起: 假设创建游戏中的一个房屋House设施,该房屋的构建由几部分组成,且各个部分富于变化。如果使用最直观的设计方法,每一个房屋部分的变化,都将导致房屋构建的重新修正.动机(Motivation): 在软件系统中,有时候面临一个复杂对象的创建工作,其通常由各个部分的子对象用一定算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合到一起的算法却相对稳定。 如何应对种变化呢?如何提供一种封装机制来隔离出复杂对象的各个部分的变化,从而保持系统中的稳定构建算法不随需求的改变而改变?意图(Intent): 将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。 -设计模式GOF 我们前面提及的流程就是子对象的一定算法,这个子对象的具体算法是经常变化的,但是复杂对象包含这个子对象是确定的,也就是说建造复杂对象的过程中,必须 包含子对象这个过程。但是这个部分“经常面临剧烈的变化”。显然,对于打开文件和打开设备,内部具体实现肯定是剧烈变化的。 子对象内部是剧烈变化的,但是复杂对象的构建流程是确定的,也就是所谓的“组合到一起算法相对稳定” 所谓“复杂对象的构建与其表示分离”,构建就是抽象出确定的流程,表示指的每个流程的具体实现。下面通过具体实例说明如何使用建造者模式。问题:通过建造者模式解决零件生产问题。一、分析流程,创建抽象类 我们综合零件的生产过程,可以抽象出如下过程。1、零件设计 2、零件工艺 3、材料准备 4、加工 5、检查 6、入库 工厂生产的零件有多种,各不相同,但是总的流程是确定的,因此需要创建一个Builder抽象类,这个类描述了所有零件的生产过程,但是对于任何实际的零件,从设计到工艺,从加工到检查,具体细节各不相同。 零件抽象类作为所有具体零件的基类,因为LV无法实现真正的抽象类,所以把零件类放在库中,并设置零件类的库属性为私有,这样在库外部无法直接访问,间接实现了抽象的效果。 零件抽象类的私有数据成员数据类型为字符串,用来描述零件的整个生产过程。 零件的整个生产过程用5个方法来描述,这些方法都是可重写的,具体零件真正的生产过程延迟到子类中实现。 上图为零件设计方法的程序框图,其它方法类似,目的是把当前过程写入到私有数据成员中,表示正在进行的过程。 接下来创建零件类的属性,用来读取存储在字符串中的运行过程。二、创建具体零件类 零件抽象类设计完成后,具体零件的实现类就很容易了,只需要继承零件抽象类,并重写其中几个方法就可以了。 我们创建了两个具体的零件,分别是齿轮和连杆,其基本流程是相同的,但是每个零件各个具体流程的实现方法是不同的,我们只是不同的字符串表示其不同的加工过程。三、创建指挥者 我们在零件抽象类中,创建了零件加工过程的各个过程,但是并没有真正体现出整个零件的加工次序,比如是先设计还是先加工等等。所以需要创建一个指挥者类, 该类私有数据成员中包括一个零件抽象类的实例,并负责具体建造的过程,指挥者保证了无论是齿轮还是连杆,都必须遵循同样的流程。 上图中,最上面部分为指挥者类的私有数据成员,存储的是零件抽象类的实例。下面部分是指挥类的属性,负责写入具体类的实例,替换存储的私有数据。 指挥者类中创建了一个方法,用来指挥具体零件的生产过程,对于任何具体零件,其生产过程都是一致的,这是抽象类中定义的可重写方法,指挥者不过是规定生产流程的次序。 上面的方法确定了零件的生产过程为零件设计、零件工艺制作、零件加工、零件检查、零件入库,最后返回一个字符串,描述整个生产过程。四、具体调用创建了上述几个类后,具体调用就非常简单了。 上面的程序框图分别创建了齿轮和连杆两个具体实例,在字符串中输出了他们整个生产过程。LVOOP之单例模式 12/14/20090 Comment(s) 单例模式:保证类只有一个实例,并提供一个全局访问点。 前面讨论过类的原型模式,这说明使用类的一大优势是类是可以创建多个实例,而且彼此之间是相互隔离的,互相之间并不影响。今天讨论的是相反的情况,即类的单一实例问题。 EXE文件、VI都存在单一实例的问题,比如我们在操作一个硬件时,一般不允许多个执行文件同时操作,这就要求该EXE 文件不能启动两次,VI 也是如此。默认的VI 设置是不可重入的,不可重入VI本身就保证了该VI 必须运行完毕后,下一次调用才能执行,所以常规VI是单一实例的。可重入VI恰恰相反,可以同时运行VI的多个实例,类也是如此,个别情况下,只允许单个实例,这就是所说的单例模式。 单例模式有两个重要的特点:一、只能创建唯一的一个实例。二、必须提供一个基于全局的访问方法,在任何场合都可以随意调用这个实例。 我们自然会想到能否用LV内置的全局变量解决这个问题,如果把类的实例存储在全局变量中,这解决了全局访问点的问题,任何场合都可以调用这个实例。但是, 这种方法有两个重大的缺陷,一是全局变量的竞争问题,更为重要的他无法满足只能创建唯一一个实例的要求。通过全局变量,并不能防止其他地方创建这个类的实 例。 常规的面向对象编程语言是这样解决的。 在类的定义中, 定义一个本身类的引用,该引用为静态变量,VB.NET 称作共享型变量,在所有类的实例中共享。LVOOP 中,我们在类中也可以定义这样的共享变量。在LV的类中,如果定义一个全局变量作为类的数据成员,这实际上限定了这个全局变量的作用范围仅限于类中。 构造函数为私有函数,这意味着无法在外部直接创建类的实例。提供了一个静态(共享)方法,通过它返回唯一的实例。如果尚未创建实例,则创建之,如果已经创建,则返回这个类的实例。 类的引用(指针)作为类的数据成员,这是一般面向对象编程语言都支持的,事实上即使面向过程的C语言中,结构类型虽然不允许把结构本身
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号