谷俭政
当前软件工程领域和软件产业界的热点技术包括原型开发方法、C/S与B/S结构、软件构件、软件复用等。本文针对这些当今软件开发的主流技术加以评述,以期对实际工作做出指导。
原型法
原型法是近年来提出的一种以计算机为基础的系统开发方法,利用原型法开发系统时首先构造一个功能简单的原型系统,然后通过对原型系统逐步求精,不断扩充完善得到最终的软件系统。
原型就是模型,原型系统就是应用系统的模型。它是待开发的实际系统的缩小比例模型,但是保留了实际系统的大部分性能。这个模型可在运行中被检查、测试、修改,直到它的性能达到用户需求为止,随之这个工作模型很快就能转换成需要的目标系统。
原型法的主要优点在于它是一种支持用户的方法,使得用户在系统生存周期的设计阶段起到积极的作用,能减少系统开发的风险。特别是在大型项目的开发中,由于用户对系统功能认识的模糊性,使得对项目需求的分析难以一次完成,往往会造成已完成的项目多次修改,应用原型法则会避免这种风险。
原型法的概念既适用于系统的重新开发,也适用于对系统的修改;利用原型法开发系统需要有良好的软件开发环境、工具的支持。原型法也可以与传统的生命周期方法相结合使用,以便扩大用户参与需求分析、初步设计及详细设计等阶段的活动,加深对系统的理解。
微软公司通常采用“同步-稳定产品开发法”进行项目开发。典型项目的生命周期包括三个阶段:
1. 计划阶段:完成项目的功能说明和进度表的制定;
2. 开发阶段:写出完整的的源代码;
3. 稳定化阶段:完成产品,使之能够批量生产。
这三大阶段以及阶段间内在的循环方法与传统的“瀑布”式开发方式很不相同,后者是由需求、详尽设计、模块化的代码设计与测试、集成测试以及系统测试组成的。而微软的三个阶段更像是风险驱动的、渐进的“螺旋”式的生命周期模型。
构造原型是在计划阶段具体说明一件新产品或一个新版本的最好方法,这从许多方面来说特别是在系统可用性方面都使开发前测试成为可能,并且有助于对与用户交互情况做出良好的理解,同时也能使产品说明更加紧凑。
微软的开发人员通常采用VB构造用户界面原型,对于构造计算机屏幕模型之类的工作,画笔(Paintbrush)也是一个很好用的工具。通过原型法可以使死板的说明变成有生命的文件。
C/S与B/S结构
管理信息系统平台模式大体上分为四种:主机终端模式、文件服务器模式、C/S模式和B/S模式。主机终端模式由于硬件选择有限,硬件投资得不到保证,已被逐步淘汰。而文件服务器模式只适用小规模的局域网,对于用户多、数据量大的情况就会产生网络瓶颈,特别是在互联网上不能满足用户要求。因此,现代企业管理信息系统平台模式应主要考虑C/S模式和B/S模式。
● C/S结构
两层结构的C/S(Client/ Server)模式在上个世纪八九十年代得到大量的应用。C/S结构由两部分构成:前端是客户机,通常是PC;后端是服务器,运行数据库管理系统,提供数据库的查询和管理。
但两层的C/S结构存在以下几个局限:它是单一服务器且以局域网为中心的,所以难以扩展至大型企业广域网或Internet;受限于供应商;软、硬件的组合及集成能力有限;难以管理大量的客户机。
因此,三层C/S结构应运而生。三层结构的C/S模式是伴随着中间件技术的成熟而兴起的,核心思想是利用中间件将应用分为表示层、业务逻辑层和数据存储层三个不同的处理层次。三个层次的划分是从逻辑上来分的,具体的物理分法可以有多种形式。
三层C/S结构具有以下优点:具有灵活的硬件系统构成;提高程序的可维护性;利于变更和维护应用技术规范;进行严密的安全管理;越关键的应用,用户的识别和存取权限设定愈重要。
● B/S结构
基于Web的B/S(Browser/ Server)方式其实也是一种客户机/服务器模式,只不过它的客户端是浏览器。
B/S结构中处于第一层的是客户端,处于第二层的是应用服务器,由一台或者多台服务器组成,该层具有良好的可扩充性,可以随着应用的需要增加服务器的数目。处于第三层的是数据层,由数据库系统和遗留系统组成。
B/S的优势在于:简化了客户端;简化了系统的开发和维护;用户操作变得更简单;适用于网上信息发布。
软件构件技术
所谓软件构件化,就是要让软件开发像机械制造工业一样,可以用各种标准和非标准的零件来进行组装。软件的构件化和集成技术的目标是:软件系统可以由不同厂商提供的,用不同语言开发的,在不同硬件平台上实现的软件构件,方便地、动态地集成。这些构件要求能互操作,它们可以放在本地的计算机上,也可以分布式地放置在网上异构环境下的不同结点上。
面向对象的方法和技术是继结构化方法之后出现的、最有代表性的软件开发方法,是当今软件开发的主流技术。但是,面向对象所提供的优点主要是针对分析、设计和源代码等软件开发阶段的,当一个面向对象的代码经过编译、连接后得到的可执行软件则是不可改变的、无法重用的。
因此,我们需要一种新的、不依赖于某种特定语言的、在二进制代码级可复用的软件“对象”,这种“对象”就是构件(Component)。
构件技术是一种软件实现的技术和方法,是对面向对象方法在二进制代码级的完善和补充。构件是由接口构成的,它把接口和接口的实现分离开了。接口是独立于语言的一种描述,它将内部的实现以及接口到实现的映射都封装起来了,外界只能通过接口描述使用构件。因此,接口用哪种语言实现也就无关紧要了。
在现有的软件市场上,有三种代表性的构件技术流派,它们分别是COM(Component Object Model,对象构件模型)、JavaBean和CORBA(the Common Object Request Broker Architecture,公共对象请求代理体系结构)。它们是由不同的机构提出的构件技术实现模型和标准,各有优缺点。
● COM
COM是由Microsoft公司推出的构件接口标准,是软件构件相互通信的一种方式,它是一种二进制和网络标准,允许任意两个组件互相通信。目前已有大量的基于COM的构件可供复用,原则上讲,这些构件可以建立在任何环境下,但现有的COM构件大多都依赖于Microsoft环境,在Unix、Macintosh等其他操作系统环境下可复用的构件还很少,Microsoft公司正在努力开发更多的在其他操作系统环境下的COM构件。
传统的应用程序在源代码级可被分割为文件、模块、类或函数等,以便于实施、修改和维护,但经编译、链接以后就生成了不可改变的二进制可执行代码,采用COM技术产生的源代码则不同。
一个COM构件是由若干个接口组成的,而一个接口则是由若干个函数的说明组成的。COM是一个二进制标准,即接口编译以后生成的二进制代码的结构要满足一定的内存块结构。该内存块结构是不依赖于任何语言的。图1表示一个拥有Fun1和Fun2函数的IX接口的内存块结构。
其中,pIX是指向IX接口的指针,通过vtbl指针(接口指针)指向接口中函数的指针数组(称为v表),v表中的元素是指向接口中函数实现的指针。后面我们将会看到函数指针在用代理-存根机制实现进程间、计算机间的接口调用时指向相应的代理。
任何语言的语法成分,只要其编译后的目标代码在结构满足图1的二进制形式结构,就称其为该构件接口的一个实现。通常情况下,大多数程序设计语言和其COM支持工具都能将相应的语法自动地映射为这样的结构,无需程序员做更多的工作。
COM是一个二进制标准。由于任何语言都要翻译成二进制机器代码才能最后执行,所以COM可以作为各种高级语言的中间桥梁,使它们可以互操作;按COM标准实现的软件也可以被所有的语言环境所共享。共享人类开发的、丰富的软件资源是提出的COM的最初动机。
● JavaBean
目前的COM技术主要是针对PC市场的不依赖于语言的软件构件技术,而JavaBean则是针对解决平台依赖性和语言依赖性这两个问题而提出来的软件构件技术标准。
关于平台依赖性问题是其他构件标准普遍存在的问题。尽管其他构件标准的接口是惟一的,即使用构件的方式是惟一的,但一个构件一旦在某种运行环境下实现就很难直接在另一种运行环境被复用。而这种平台依赖性问题对进一步提高软件复用力度却是至关重要的。
由于Java本身在全球软件界的影响,特别是Java独立于平台的、适宜于在Internet、易于构造B/S应用等等特点,Javasoft公司利用Java特殊的byteCode机制,很好地解决了其他构件标准难以解决的平台依赖性问题,推出了它们自己的构件接口标准JavaBean。正像JavaSoft所描述的JavaBean是“一次性编写,在任意地方可运行,在任意地方可重用”。
JavaBean的构件模型主要包括:构件和容器。模型的其他部分还包括事件处理、持续性、布局以及应用程序建立器(一种可视化的工具)等,这些都是通过JavaBean构件的标准接口实现的。
JavaBean构件有时也称为JavaBean或Bean。它是由接口构成的,接口是由方法组成的。容器能够使构件组合在一起并相互作用。这种机制主要是为了界面构件提出的,它本身也是一个构件,以便嵌套组合产生复杂的可视化GUI。JavaBean的主要特征为:
1. 属性管理
根据属性的使用类型可将其分为:一般属性、索引属性、依附属性和约束属性,通过一些标准的命名约定定义它们相应的访问方法,使JavaBean API能用统一的方式对属性进行管理。其中,依附属性是基于自身值的变化而向感兴趣的部分提供通知的属性。约束属性是一种在接收更改之前能使感兴趣的部分对新属性值执行有效检查的属性。
2. 内省功能
内省功能是构件的内部结构(属性、方法和事件)展现给外部的机制。不同于COM,JavaBean不需要构件开发者开发这种额外的工作,它只需要开发者对构件的属性、方法和事件的命名和类型符号遵守一个约定,通过标准的JavaBean API就可了解到bean的任何内部信息。
JavaBean的事件处理模型是基于现存的AWT事件处理模型的。它决定bean如何对它自身状态的变化做出反应,以及决定如何将这些变化传递给应用程序和其他bean。通过JavaBean API将一个事件接收器(处理某个事件的应用程序或其他bean)注册到该事件上,完成外部对事件的控制。这是将bean组合起来的有效方法。
Java与JavaBean的区别是:Java是在源代码级的复用;而JavaBean是在目标代码级的复用,并且,通过JavaBean提供的标准接口,为在目标代码级的动态组装、版本升级、维护提供保证,并可利用一些相应的可视化工具方便、有效地定制JavaBean和建立应用程序。
尽管JavaBean是作为一种通用的构件模型提出来的,但它更主要地还是为解决可视化构件而设计的一套系统,它类似于Microsoft的ActiveX。严格地讲,目前的JavaBean在不同语言之间提供的互操作性方面是很弱的,它只是提供了在Java环境下的二进制代码共享机制。增强JavaBean与其他构件技术之间的互操作是JavaBean今后发展的一个主要课题。
● CORBA
CORBA是由OMG(对象管理组)1990年首次为了解决分布式、异质的软件和硬件环境下对象之间的互操作问题而提出的、基于中间件的构件技术。CORBA有两个重要的特点:面向对象技术与分布式计算的结合;代理机制的中间件技术。
1. 面向对象与分布式技术的结合
CORBA是为了解决分布式问题而提出的分布式对象计算模型。利用计算机网络进行分布式计算可以共享资源、平衡大型计算的负载等。但是,传统的分布式计算模型还不够成熟:客户/服务关系不灵活、远程服务层次太低、用户使用不透明。面向对象中的对象是一个相对独立的软件实体,它有自己的内部状态和清晰的对外接口。但传统的面向对象模型的实现,只能在单计算机上进行。CORBA将这两者有机地结合起来了。在CORBA中,对象是分布式计算模型中理想的节点描述模块,对象既可以是“客户”,也可以是“服务器”,它可自由地分布于计算机网络上。通过CORBA,对象可网络透明地相互访问,CORBA屏蔽了位置信息和计算机的软硬件环境,因此,CORBA建立了一个统一的分布式软件开发平台。
2. 代理机制的中间件——对象请求中介(Object Request Broker,简称ORB)
作为一种构件技术,CORBA要解决的另一个重要问题是二进制代码之间的互操作问题。
不同于COM/DCOM技术,CORBA提供了一种中间的代理机制,将构件的接口与构件的实现分离开了。服务对象实现后,就将其接口登记在CORBA的代理中,客户对象按照代理中的接口描述访问服务对象,而不关心服务对象使用什么语言、在什么地方、在什么软硬件环境下实现的。这些工作都由代理自动地、透明地为客户对象完成。这种机制还可提供客户与服务器之间动态匹配、一个服务器为多个客户服务等功能。
ORB提供的机制是良好的,也提供了足以使客户和服务器通信的服务,但这些服务是很低级的。用户要熟练地掌握它们不是一件容易的事情,而且这些繁锁的过程经常重复。因此,CORBA对经常使用的服务封装内部的细节,提供简化用户使用的、方便的、标准的对象服务。对象服务是CORBA非常重要的一部分,是对ORB功能的扩充和补充。CORBA提供的15种服务可分为三大类:分布式系统相关的服务,如命名服务、事件服务、安全性服务和交易器服务;数据库相关的服务,如事务处理、属性、集合、关系、查询、持久性、外表化、并发等服务;一般服务,如生命期、计时、特许等服务。大多数应用都是在这些服务的基础上建立的。
公共设施是CORBA提供的另一种比对象服务更高一层的框架服务。它是特定应用领域的框架复用,如复合文档构件设施等。CORBA的公共设施还很少,还有大量的设施需要集成,如图形系统、移动代理等。
CORBA没有定义二进制代码的标准,而是在高层定义了一个标准的接口描述语言IDL,并通过扩展机制提供各种语言到IDL之间的映射,以IDL为中间的桥梁,达到各种语言之间的互操作。
● 三种构件模型的特点
COM是一种二进制标准的构件技术,它实现简单、实用,但要完成真正意义的、独立于硬件和操作系统的二进制标准,还有大量的工作要做。目前,COM还只是Microsoft环境下的二进制标准。
CORBA是一种以IDL为桥梁、基于ORB的中间件的构件技术。它是以IDL为标准的,与实现构件接口的语言、软件平台和硬件平台无关。但它却无法支持Internet上大量的移动计算的需求,一个构件的实现是与软硬件平台相关的,即一个构件的实现是不能在网上移动的。
JavaBean是一种能提供在网上移动的构件技术,它通过bytecode技术,提供在“任何地方运行,任何地方重用”的功能,但它却是与语言相关的。
从软件体系结构的角度看,构件技术中的构件只是提供一个软件模块的实现,作为一个软件系统,它还需要连接子(connector)将软件模块组织成一个整体。有各种各样组织软件模块的形式:管道和过滤器、层次、基于事件的隐式调用等等。管道和过滤器模型最容易实现软件模块的集成,但只能处理简单的、流式的应用,没有普遍性。层次模型可提供不同级别的抽象,但层与层之间存在着紧密的耦合,而且,这种模型也没有普遍性。基于事件的隐式调用的方式是,构件向系统发出请求,已经向系统注册响应该事件的构件就响应该事件。这种模型将调用者和被调用者彻底地分开,这种软件体系结构模型具有很强的灵活性,也具有通用性。
构件技术的初衷是为了能充分地利用在各种环境下,用各种程序设计语言开发的软件模块而提出的一种二进制代码级的软件复用技术。通过接口这种不依赖于具体语言的中性机制,使各种语言之间可以互操作,也就是说一种语言可通过接口访问另一种语言开发的软件,而不需要移植工作,这大大地提高了软件的复用程度。
软件复用技术
软件复用就是将已有的软件成分用于构造新的软件系统。可以被复用的软件成分一般称作可复用构件,无论对可复用构件原封不动地使用还是作适当的修改后再使用,只要是用来构造新软件,则都可称作复用。软件复用不仅仅是对程序的复用,它还包括对软件生产过程中任何活动所产生的制成品的复用。但如果是在一个系统中多次使用一个相同的软件成分,则不称作复用,而称作共享;对一个软件进行修改,使它运行于新的软硬件平台也不称作复用,而称作软件移值。
● 软件复用级别
未来最有可能产生显著效益的复用是对软件生命周期中一些主要开发阶段的软件制品的复用,按抽象程度的高低,可以划分为如下的复用级别:
1.代码的复用
包括目标代码和源代码的复用。其中目标代码的复用级别最低,历史也最久,当前大部分编程语言的运行支持系统都提供了连接(Link)、绑定(Binding)等功能来支持这种复用。源代码的复用级别略高于目标代码的复用,程序员在编程时把一些想复用的代码段复制到自己的程序中,但这样往往会产生一些新旧代码不匹配的错误。想大规模实现源程序的复用只有依靠含有大量可复用构件的构件库。如“对象链接及嵌入”(OLE)技术,既支持在源程序级定义构件并用以构造新的系统,又使这些构件在目标代码的级别上仍然是一些独立的可复用构件,能够在运行时被灵活地重新组合为各种不同的应用。
2.设计的复用
设计结果比源程序的抽象级别更高,因此它的复用受实现环境的影响较少,从而使可复用构件被复用的机会更多,并且所需的修改更少。这种复用有三种途径:第一种途径是从现有系统的设计结果中提取一些可复用的设计构件,并把这些构件应用于新系统的设计;第二种途径是把一个现有系统的全部设计文档在新的软硬件平台上重新实现,也就是把一个设计运用于多个具体的实现;第三种途径是独立于任何具体的应用,有计划地开发一些可复用的设计构件。
3.分析的复用
这是比设计结果更高级别的复用,可复用的分析构件是针对问题域的某些事物或某些问题的抽象程度更高的解法,受设计技术及实现条件的影响很少,所以可复用的机会更大。复用的途径也有三种,即从现有系统的分析结果中提取可复用构件用于新系统的分析;用一份完整的分析文档作输入产生针对不同软硬件平台和其他实现条件的多项设计;独立于具体应用,专门开发一些可复用的分析构件。
4.测试信息的复用
主要包括测试用例的复用和测试过程信息的复用。前者是把一个软件的测试用例在新的软件测试中使用,或者在软件作出修改时在新的一轮测试中使用。后者是在测试过程中通过软件工具自动地记录测试的过程信息,包括测试员的每一个操作、输入参数、测试用例及运行环境等一切信息。这种复用的级别不便和分析、设计、编程的复用级别作准确的比较,因为被复用的不是同一事物的不同抽象层次,而是另一种信息,但从这些信息的形态看,大体处于与程序代码相当的级别。
由于软件生产过程主要是正向过程,即大部分软件的生产过程是使软件产品从抽象级别较高的形态向抽象级别较低的形态演化,所以较高级别的复用容易带动较低级别的复用,因而复用的级别越高,可得到的回报也越大,因此分析结果和设计结果在目前很受重视。用户可购买生产商的分析件和设计件,自己设计或编程,掌握系统的剪裁、扩充、维护、演化等活动。
● 软件复用的困难
软件复用各方面的困难,无论是技术问题还是非技术问题,都影响着软件复用的广泛实行。
首先构件与应用系统之间的存在差异。一些开发者开发的构件,要做到在被另一些人开发的系统中使用时正好合适,从内容到对外接口都恰好相符,或者作很少的修改,这不是一件简单的事。
其次构件要达到一定的数量,才能支持有效的复用,而大量构件的获得需要有很高的投入和长期的积累;当构件达到较大的数量时,使用者要从中找到一个自己想要的构件,并断定它确实是自己需要的,也不是一件轻而易举的事;基于复用的软件开发方法和软件过程是一个新的研究实践领域,需要一些新的理论、技术及支持环境,目前这方面的研究成果和实践经验都不够充分。
最后,人的因素、管理因素、教育因素、法律因素等等都使软件的复用更为困难。
●面向对象方法对软件复用的支持
支持软件复用是人们对面向对象方法寄托的主要希望之一,也是这种方法受到广泛重视的主要原因之一。面向对象方法之所以特别有利于软件复用,是由于它的主要概念及原则与软件复用的要求十分吻合。
面向对象方法从面向对象的编程发展到面向对象的分析与设计,使这种方法支持软件复用的固有特征能够从软件生命周期的前期阶段开始发挥作用,从而使面向对象方法对软件复用的支持达到了较高的级别。与其他软件工程方法相比,面向对象方法的一个重要优点是,它可以在整个软件生命周期达到概念、原则、术语及表示法的高度一致。这种一致性使得各个系统成分尽管在不同的开发与演化阶段有不同的形态,但可具有贯穿整个软件生命周期的良好映射。这一优点使面向对象方法不但能在各个级别支持软件复用,而且能对各个级别的复用形成统一的、高效的支持,达到良好的全局效果。做到这一点的必要条件是,从面向对象软件开发的前期阶段——面向对象分析就把支持软件复用作为一个重点问题来考虑。运用面向对象分析方法所定义的对象类具有适合作为可复用构件的许多特征,面向对象分析结果对问题域的良好映射,使同类系统的开发者容易从问题出发,在已有的面向对象分析结果中发现不同粒度的可复用构件。
●复用技术对面向对象方法的支持
面向对象的软件开发和软件复用之间的关系是相辅相成的。一方面,面向对象方法的基本概念、原则与技术提供了实现软件复用的有利条件;另一方面,软件复用技术也对面向对象的软件开发提供了有力的支持。
1.类库
在面向对象的软件开发中,类库是实现对象类复用的基本条件。人们己经开发了许多基于各种OOPL的编程类库,有力地支持了源程序级的软件复用,但要在更高的级别上实现软件复用,仅有编程类库是不够的。实现面向对象分析结果和面向对象设计结果的复用,必须有分析类库和设计类库的支持。为了更好地支持多个级别的软件复用,可以在面向对象分析类库、面向对象设计类库和面向对象编程类库之间建立各个类在不同开发阶段的对应与演化关系。即建立一种线索,表明每个面向对象分析的类对应着哪个(或哪些)面向对象设计类,以及每个面向对象设计类对应着各种面向对象编程语言类库中的哪个面向对象编程类。
2.构件库
类库可以看作一种特殊的可复用构件库,它为在面向对象的软件开发中实现软件复用提供了一种基本的支持。但类库只能存储和管理以类为单位的可复用构件,不能保存其他形式的构件;但是它可以更多地保持类构件之间的结构与连接关系。构件库中的可复用构件,既可以是类,也可以是其他系统单位;其组织方式,可以不考虑对象类特有的各种关系,只按一般的构件描述、分类及检索方法进行组织。在面向对象的软件开发中,可以提炼比对象类粒度更大的可复用构件,例如把某些结构或某些主题作为可复用构件;也可以提炼其他形式的构件,例如use case 或交互图。这些构件库中,构件的形式及内容比类库更丰富,可为面向对象的软件开发担供更强的支持。
3.工具
有效地实行软件复用需要有一些支持复用的软件工具,包括类库或构件/构架库的管理、维护与浏览工具,构件提取及描述工具,以及构件检索工具等等。以复用支持为背景的面向对象分析工具和面向对象设计工具在设计上也有相应的要求,工具对面向对象分析/面向对象设计过程的支持功能应包括:从类库或构件/构架库中寻找可复用构件;对构件进行修改,并加入当前的系统模型;把当前系统开发中新定义的类(或其它构件)提交到类库(或构件库)。