第八章 软件复用 一、复习要求 1. 了解软件复用的概念、过程和意义。 2. 了解软件复用的类型、复用的目标和内容。 3. 了解针对复用的过程模型和论域工程。 4. 了解可复用构件的构造原则和质量标准。 5. 了解可复用构件库的组织,包括可复用构件的3C模型。 6. 了解软件的分层式体系结构。 7. 了解软件构件的复用过程(包括构件的检索与提取、理解与评价和修改) 8. 了解面向对象的软件复用技术 9. 了解支持软件复用的CASE工具需求 二、内容提要 1. 软件复用的概念、过程和意义 (1) 软件复用的概念 对建立软件目标系统而言,所谓复用(Reuse),就是利用某些早先开发的对建立新软件系统有用的软件元素来生产新系统。它是一项活动,而不是一个对象。这里所说的软件元素可以包括需求规格说明、设计过程、设计规格说明、程序代码、测试用例、度量等等。对于新的软件开发项目而言,它们或者是构成新软件系统的构件,或者是在软件开发过程中发挥某种作用。通常将这些软件元素称为可复用构件。 早在50年代用机器语言编写程序的时期,计算正弦、余弦、对数等的标准子程序包就开创了复用的先河。到70年代的早期,在语言、数据结构、操作系统、程序变换等方面各种技术的发展,都与代码的复用有关。当时,复用的应用领域有限,软件的复用问题没有提到很重要的位置上来讨论。70年代的中期和后期开始,为了缓解软件危机,许多人寄希望于软件复用技术,因为在提高软件生产率与质量,以及减少软件开发时间和成本的努力中软件复用已经成了关键因素。当前,美、日一些大公司的资料表明,软件复用率最高可望达到90%,而且软件复用使得企业在及时满足市场、软件质量、软件开发费用和维护费用等方面得到显著的改进。 为了保证软件的复用,需要注意解决的问题主要有: ( 复用必须以对被复用对象的理解为基础; ( 如何表达对软件构件的需求; ( 如何寻找有关的软件构件; ( 如何识别是否满足要求; ( 如何调整或修改构件使之满足要求; ( 如何组装到新系统中; ( 如何保证结果的正确性; ( 如何进行效益的定量估算。只有当复用能带来效益时人们才会考虑复用。 为了能够在软件开发过程中复用现有的软件构件,必须在此之前不断地进行可复用构件的积累,并且将它们组织成可复用构件库。因此,软件复用不但要讨论如何检索所需的软件构件以及如何对它们进行必要的修剪,而且还要解决如何选取可复用构件、如何组织可复用构件库等问题。 (2) 软件复用的过程和意义 软件复用可以区分为横向复用和纵向复用。横向复用是复用不同应用论域中的软件元素,例如数据结构、排序算法、人机界面构件等。标准函数库是一种典型的原始的横向复用机制。纵向复用是在一类具有较多公共性的应用论域之间复用软件构件。由于在两个截然不同的应用论域之间进行软件复用潜力不大,所以纵向复用受到广泛关注。 纵向复用活动的主要关键点在于论域分析:根据应用论域的特征和相似性,预测软件构件的可复用性。一旦根据论域分析确认了软件构件的可复用价值,即可进行软件构件的开发,并对具有可复用价值的软件构件做一般化处理,使它们能够适应新的类似的应用论域。然后将软件构件和它们的文档存入可复用构件库,成为可供未来开发项目使用的可复用资源。这些步骤构成软件构件的构造活动。这是一个不断积累、不断完善软件构件的渐进过程。 随着可复用构件的不断丰富,可复用构件库的规模会不断扩大,这样,必须考虑如何组织库的结构以保持较高的检索效率。可供选择的软件构件从库中被检索出来之后,用户还必须理解它的功能或行为,以判定它是否真正适合于当前的应用。必要时,可考虑对某个与期望的功能或行为匹配程度最好的可复用构件进行少量修改,甚至可将修改后的构件再加到可复用构件库中。上述的软件复用的方法如图8.1所示。 软件复用的过程可借助计算机的帮助。支持软件复用的CASE 工具的主要工作是:用某种组织形式实现可复用构件的存储,提供友好的人机界面,帮助用户浏览、检索和修改可复用构件库,对用户感兴趣的软件构件进行解释。事实上,几乎所有的软件复用活动都是在CASE工具的帮助下进行的。 使用复用技术可以减少软件开发活动中大量的重复性工作,这样就能够提高软件生产效率,降低开发成本,缩短开发周期。同时。由于可复用构件大都经过严格的质量验证,并在实际运行环境中得到检验,因此,复用软件构件有助于改善软件质量。此外,大量使用可复用构件,软件的灵活性和标准化程度也可望得到提高。 2. 软件复用的类型 软件复用的范围不仅涉及源程序代码,Caper Jones定义了十种可能复用的软件要素: ① 项目计划:软件项目计划的基本结构和许多内容(如SQA计划)都可以跨项目复用。这样可减少制定计划的时间,也可降低与建立进度表、风险分析及其他特征相关的不确定性。 ② 成本估计:由于不同项目中常包含类似的功能,所以有可能在极少修改或不修改的情况下,复用对该功能的成本估计。 ③ 体系结构:即便应用论域千差万别,但程序和数据体系结构大同小异。因此,可以创建一组类属的体系结构模板(例如事务处理结构),将这些模板作为可复用的涉及框架。 ④ 需求模型和规格说明:类和对象的模型和规格说明显然可以复用。此外,用传统软件工程方法开发的分析模型(如数据流图)也可以复用。 ⑤ 设计:用传统方法开发的体系结构、数据、接口和过程化设计都可以复用。另外,复用系统和对象的设计是屡见不鲜的。 ⑥ 源程序代码:验证过的程序构件(用兼容的程序设计语言书写)是可以拿来复用的。 ⑦ 用户文档和技术文档:即便特定的应用不同,但也经常有可能复用用户文档和技术文档中的大部分内容。 ⑧ 用户界面:这可能是最广泛被复用的软件元素。如经常复用GUI的软件构件。因为它可占到一个应用的60%的代码量,所以复用的效果最明显。 ⑨ 数据结构:经常被复用的数据结构包括:内部表、列表和记录结构,以及文件和完整的数据库。 ⑩ 测试用例:只要将设计或代码构件定义成可复用构件,相关的测试用例就应当成为这些构件的“从属品”。 表8.1给出的数据(来自军方的一些系统项目)表明1美元投资在4年后的回报。Jones对复用的整体影响给出高度评价:“复用所有10种软件要素的总计值可以产生可能是任意已知的软件技术种的最好回报。” 表8.1 软件复用在4年后的回报价值 可复用软件要素  4年后的回报  可复用软件要素  4年后的回报   项目计划  $ 2.00  源程序代码  $ 6.00   成本估计  $ 3.00  用户文档和技术文档  $ 1.50   体系结构  $ 1.50  用户界面  $ 1.00   需求模型和规格说明  $ 3.00  数据结构  $ 3.50   设计  $ 5.00  测试用例  $ 3.50   需要注意的是,复用还可以扩展到以上所讨论的可交付的软件要素之外,它还包含了软件工程过程中的元素。特定的分析建模方法、检查技术、测试用例设计技术、质量保证过程,以及很多其它软件工程实践都可以被“复用”。例如,如果某项目组有效地应用了某种软件工程方法,那么在开发其它项目时可以复用该方法。为帮助潜在的该方法的使用者选择这个方法,应定义一组功能描述,以帮助人们作出适当的决策。 3. 论域工程 (1) 针对复用的过程模型 针对复用的过程模型如图8.2所示。这种过程模型强调并行的工作方式。以这种方式,论域工程和基于构件的应用开发同时进行。 论域工程创建应用论域的模型,这个模型将成为软件工程流中分析用户需求的基础。软件体系结构(及相应的结构点)为应用的设计提供了输入。最后,当可复用构件构造好并放入可复用构件库中(在论域工程中进行)之后,它们就可以在软件构造活动中供软件开发人员使用。 (2) 论域工程 论域工程的目的是标识、构造、分类和传播一组软件要素。从软件工程的观点来看,论域就是向应用软件提供应用需求的问题和背景知识。论域工程的主要任务就是针对单个或一族相似的论域,以软件复用为目标,探寻并挖掘论域或论域族中能够为多个应用软件系统共用的软件要素,并对它们进行结构化组织,放入可复用构件库,以备复用。 论域工程包括三个主要的活动:分析、构造和传播。 ① 论域分析过程 论域分析与常规的需求分析活动有相似之处,它们都是软件开发中直接基于应用论域的开发活动,并且都要完成程度不同的论域建模任务。但是论域分析必须具有比需求分析更为广阔的视角:不仅要服务于当前的应用,而且要从论域的历史项目中发现这些项目之间的共同点和差异点,并放眼于同类或相似应用论域的未来软件项目。 图 8.2 针对复用的过程模型 论域分析的过程如下: ( 定义将要研究的论域; ( 分类从论域中抽取出来的项; ( 收集论域中应用的有代表性的样本; ( 分析样本中的每一个应用; ( 开发对象的分析模型。 应当注意的是,论域分析适合于任何一种软件工程范型。Prieto-Diaz扩展了上面论域分析的第2个步骤,建议了一个有8个步骤的标识和分类可复用软件构件的方法: ( 选择特定的功能或对象; ( 抽象功能或对象; ( 定义分类方法; ( 标识公共特征; ( 标识特定的关系; ( 抽象关系; ( 导出功能模型; ( 定义论域语言。 论域语言提供了在论域中进行应用的规格说明和构造的手段。下面给出一个检查表,以确定哪些软件要素可以成为可复用的构件。 ( 构件的功能在未来的实现工作中需要吗? ( 在论域中构件功能的公共性如何? ( 在论域中存在构件功能的副本吗? ( 构件是否依赖于硬件? ( 在不同的实现之间硬件是否保持不变? ( 硬件细节能否移到另一个构件中吗? ( 设计为下一步的实现进行过足够的优化吗? ( 我们能够把一个不可复用的构件参数化以使其成为可复用的构件吗? ( 构件是否可以仅仅经过少量修改就能够在很多实现中复用吗? ( 通过修改实现复用是可行的吗? ( 一个不可复用的构件能否通过分解以产生一组可复用的构件吗? ( 针对复用的构件分解有效到什么程度? ② 论域特征 有时很难确定一个潜在可复用的软件构件在某种特定的情况下是否确实可以使用。为了解决这个难题,有必要定义一组可以为论域中所有软件共享的论域特征。论域特征定义了存在于论域中的所有产品的类属属性。例如,类属属性可能包括有:安全性∕可靠性的重要性、程序设计语言、处理中的并发性,以及其它许多内容。 若设某一可复用软件构件p的论域特征的集合为 {Dp},集合中每一项Dpi表示某一特定的论域特征。赋予Dpi的值表示该论域特征对软件的相关程度,共分为5个等级: ( 与新软件是否可复用没有相关性。 ( 仅在不寻常的情况下相关。 ( 相关。此时可以修改软件构件以使其可以被复用。 ( 显著相关,且若新软件不具有此特征则复用是低效的。但复用仍有可能。 ( 显著相关,且若新软件不具有此特征则复用是无效的。此时不推荐复用。 如果想要在某应用论域中构造一个新软件w,可为它导出一组论域特征,然后在Dwi与Dpi之间进行比较,以决定既存的软件构件p是否可以有效地在应用w中复用。 表8.2列出典型的对软件复用可能有影响的论域特征,为了有效地复用软件构件,必须考虑这些论域特征。 表8.2 影响复用的论域特征 产 品 过 程 人 员   需求稳定性  过程模型  动机   并发软件  过程符合性  教育   内存限制  项目环境  经验∕培训   应用大小  进度限制  ( 应用论域   用户界面复杂性  预算限制  ( 过程   程序设计语言  生产效率  ( 平台   安全性∕可靠性   ( 语言   寿命需求   开发队伍   产品质量   生产效率   产品可靠性     ③ 结构建模和结构点 结构建模是一种基于模式的论域工程方法。使用该方法的前提是:每个应用论域有可在应用间重复的模式(功能的、数据的、行为的),它们具有复用的可能。那么,什么是结构建模呢?Pollak和Rissman这样描述:结构模型由数量不多的一些结构元素构成,用这些结构元素可明确地表示交互的模式。使用结构模型的系统体系结构可以通过由这些模型元素组成的多声部合唱来特征化。这样,许多体系结构单元都可以通过这些元素中的一些简单的交互模式来描述。 每一个应用论域都可以一个结构模型来特征化。如飞行器电子设备系统虽然在细节上有很大的不同,但在这个论域中的所有的现行软件都有相同的结构模型。因此,结构模型是一种能够而且也应该跨越该论域所有应用的可复用的体系结构要素。 结构点是结构模型中的各个不同的构成成分,用于描述系统体系结构中的模式。它有3个特征: ( 结构点是一个抽象,它应当有有限数量的实例。若用面向对象的术语来陈述,它的类层次的规模应比较小。此外,该抽象应当在论域的各个应用中重复出现,否则,验证、文档化和传播结构点的代价可能是不划算的。 ( 使用结构点的管理规则应是容易理解的,使用结构点的界面应比较简单。 ( 结构点的实现应做到信息隐蔽,将所有在结构点内部包含的复杂性封装(或隔离)在结构点内部。这样,可以减少整个系统的感知复杂性。 4. 可复用构件的构造原则和质量标准 论域分析的结果为可复用构件的选取提供了指导原则。一旦确定了某些软件元素应当称为可复用构件并要加入到可复用构件库中,软件人员就必须实际构造它们。由于软件构件的生存期将跨越开发项目,甚至应用论域,因此,可复用构件必须更为通用、更容易组装到新的软件系统中、再新的运行环境下能表现出更好的健壮性。 代码极复用时最简单,也是用得最多的。但可复用软件构件不仅包括代码级构件,它还应涵盖论域知识、需求分析文档、设计文档、测试方案、测试用例等。 (1) 需求和设计级的软件构件 需求级软件构件通常包括问题(及子问题)描述、有关的论域知识、相应的需求规格说明。问题描述及论域知识均使用论域语言,必要时可辅以结构化的自然语言。 类似地,设计级软件构件包括设计规格说明(片段)、设计决策描述、相应的设计文档(如总体设计方案、抽象算法)。这时,若能将需求级的软件构件和设计级的软件构件相结合,使需求级软件构件和设计级软件构件的复用同时发生,就能够简化对这些软件构件的理解和组装过程。 需求级和设计级软件构件的开发必须遵循以下两条原则: ( 将构件应用的上下文与构件严格分离; ( 利用抽象化、参数化等手段提取公共特征,增强构件对未来不同应用项目的适应能力。 需求级、设计级与代码级软件构件相结合,有助于代码级软件构件的提取和理解。借助较高抽象级别的软件构件可望提高复用的效能,因为这样不仅能够复用代码,而且能够复用需求模型和设计方案。 (2) 代码级的软件构件 代码级复用是迄今为止研究最深入、应用最广泛的复用技术。代码级软件构件不仅应包含通常的程序代码段,还应辅以相应的注释和上下文说明。这些辅助可以用结构化语言或其它标识机制描述,但最好以相应的需求级或设计级软件构件的形式出现。传统上,代码级软件构件的主体是子程序(过程或函数)。现在,在基于对象和面向对象程序设计语言及相应的开发环境下,软件构件可以用Ada程序包或C++类来实现。 开发代码级软件构件与通常的程序设计活动不同,其主要区别在于:软件人员必须运用各种抽象化手段,以发掘公共特征,分离构件的应用上下文、功能和行为,从而提高可复用性。典型的抽象方法有如下3种。 ( 功能抽象:软件构件的功能由接口说明中的输入―关系确定,实现细节对构件的使用者隐藏起来; ( 数据抽象:在功能抽象的基础上进一步隐藏除接口参数外的所有数据。构件的功能或行为由输入参数和构件自身记忆的内部状态决定。构件的内部状态可由构件的内部操作来更新。面向对象程序设计语言中的“类”是一种典型的基于数据抽象的软件构件。 ( 过程抽象:在数据抽象的基础上进一步实现在同一软件构件上并发执行的多个线程的无关性。软件构件提供端口,以便为多个用户同时访问软件构件中的资源进行同步控制。访问请求首先进入等待队列,软件构件就绪后,从队列中取出请求逐个执行。使用构件的多个线程之间通过全局共享数据或消息传递进行信息交换。软件构件的设计必须保证构件接口元素的功能和行为在语义上的正确性,不管各线程操作序列之间的相对时序如何变化。 (3) 程序设计的主要原则 可复用性、可理解性、正确性和易组装性是衡量软件构件质量的重要标准。这些标准都与构件开发过程中的程序设计风格密切相关。对于代码级软件构件的开发者,必须注意遵循以下的程序设计原则。 ① 可复用性与易组装性 ( 抽象化、参数化、模板化; ( 显式建立构件的外部接口,保证接口在语法上和语义上的清晰性; ( 除参数外,接口中的成分不应与运行环境相关; ( 使用构件的信息应与构件的实现细节相分离; ( 构件接口的使用方式、功能和行为模式应遵循论域分析所确立的公共标准。 ② 正确性 ( 使用显式的、标准的、完备的出错处理机制; ( 使用强类型的程序设计; ( 在构件上附加重要的测试数据和测试报告。 ③ 可理解性 ( 提供完全的、精确的文档和程序注解; ( 构件内部的结构、数据和控制流程必须标准化; ( 使用统一的命名规则和语法约定。 (4) 软件构件的质量保证 由于软件构件将在多种硬件和软件环境下运行,因此,除采用软件工程的一般的质量保证措施之外,还要针对可复用构件的特征进行特别的质量保证。 ① 构件的开发者应当利用现有的硬件、软件,在尽可能多的环境中进行各种标准测试。但是。由于条件的限制及未来运行环境的不可穷举性,这种方法对于构件的质量保证并不充分,必须与其它方法配合使用。 ② 在构件的设计过程中必须预先考虑构件对于各类可能的硬件环境的可移植性和对于不同软件环境的适应能力。根据设计制定相应的编程原则,并在编程的过程中贯彻始终。 ③ 应当尽可能将构件的与环境有关的因素抽象成为构件的参数,或者可将这些因素作为使用构件的约束条件在接口说明中详细阐述,甚至可以将这些约束条件标识成精确的逻辑断言插装到构件的源程序中。 ④ 对可能引发移植性错误和适应性错误的出错源进行分类,针对每一类出错源制定相应的防范和测试措施。移植性错误包括数值计算错误、多任务调度错误、内存使用错误等;适应性错误包括并发性错误、重名错误、表达式求值顺序错误等。针对每一类出错源制定相应的防范和测试措施与硬件、软件环境密切相关。 ⑤ 制订并执行统一的、良好的程序设计风格。这对于确保构件质量,提高可复用性、可理解性和易组装性有重要的意义。 ⑥ 成立构件质量保证小组。其主要任务是:制订构件合格的标准和构件质量保证计划,对构件开发过程进行监控,保证上述措施的落实。 5. 可复用构件库的组织 需要对收集和开发的软件构件进行分类,然后把它们放入到可复用构件库的适当为止。软件构件的分类方法和相应的构件库结构对构件的检索和理解有极为深刻的影响,就是说,可复用构件库的组织应当便于构件的存储和检索。 复用技术对可复用构件库组织方法的要求是: ( 支持构件库的各种维护操作。增、删、更新构件库应当尽量不影响构件库的结构; ( 不仅能够支持精确匹配,还应能支持相似构件的查找; ( 不仅能够进行简单的语法匹配,而且能够查找在功能和行为上等价或相似的构件; ( 对应用论域(族)有较强的描述能力和较好的描述精确度; ( 便于库管理员和用户使用; ( 具备可自动化的潜力。 (1) 枚举分类 此方法通过定义一个层次结构类描述构件。在这个层次中定义软件构件的类以及不同层次的子类。真实的构件都被罗列在枚举层次中任一路径的最低层。例如,对窗口操作的枚举层次可能是: window operations display open menu-based openWindow system-based sysWindow close via pointer …… resize via command setWindowSize, stdResize, shrinkWindow via drag pullWindow, StretchWindow up/down shuffle …… move …… 枚举分类模式的层次结构使得它易于理解和使用。但在建立层次之前,必须进行论域工程,这样层次中各个项可以有充足的知识以供使用。 (2) 关键词分类 此方法的基本思想是:根据论域分析的结果,将应用论域(族)的概念按照从抽象到具体的顺序,逐步分解树形结构或有向无回路图结构。每个概念用一个描述性的关键词表示。不可再分解的原子层的包含隶属于它的某些软件构件。图8.3给出了可复用构件库的关键词分类结构,它支持图形用户界面设计。 当加入新的构件时,库管理员必须对构件的功能或行为进行分析,在浏览上述关键词分类结构的同时,将构件置于最合适的原子层关键词之下。如果无法找到构件应从属的关键词,可以扩充现有的关键词分类结构,引进新的关键词。但库管理员必须保证新关键词有相应的论域分析的结果作为支持。 图8.3 关键词分类结构示例 (3) 多面分类 此方法由3部分构成:多面分类机制、同义词库和概念距离图。 ① 多面分类机制:分析论域范围并定义若干用于描述一个构件特征的“面”,每个“面”包含若干“概念”,它们表述构件在“面”上的基本特征。这些特征根据它们的重要性排队。“面”可以描述构件执行的功能、被操作的数据、构件应用的上下文以及任何其它特征。描述某一构件的“面”的集合称为面描述子。通常,限制面的描述不超过7到8个面。 作为一个简单的在构件分类中使用“面”的例子,面描述子的模式可以是: { 功能,对象类型,系统类型 } 面描述子中每一个“面”可含有1个或多个特征值,这些值一般是描述性的关键词。例如,若功能(function)是某一构件的一个面,赋与此面的典型值可能是: function = ( copy, from ) or ( copy, replace, all ) 使用多重面特征值可使原始的函数copy充分地细化。 ② 同义词库:意义相同或相近的若干词汇组成同义词库。所有词汇按照隶属于“面”的“概念”分组,在任一时刻点,每个“概念”可用组内的某一同义词汇作为标识载体。 ③ 概念距离图:用于度量每个“面”中“概念”的相似性程度。属于每个“面”的一般化概念与其中的两个或多个“概念”以加权边相连接,两个“概念”的相似性由它们之间的最短加权路径上的加权距离确定,附加于边上的权值体现了“概念”之间的差异程度。 图8.4 多面分类法的组成 采用多面分类法进行可复用构件库的组织,必须在存储软件构件的同时,表示并存储多面分类机制、同义词库和概念距离图。例如,可以采用关系数据库中的表格来描述它们。多面分类法的所有语法构件(“面”、“概念”、同义词、一般化概念、差异性权值)均取材于论域分析的结果。当需要在可复用构件库中加入新的构件时,库管理源必须对构件的功能、行为进行深入分析,利用现有的多面分类结构确定构件的描述子,对每个“面”选取合适的“概念”作为特征描述。必要时可以考虑增加新的“概念”,此时必须根据新“概念”完善同义词库和概念距离图。 (4) 超文本组织法 超文本方法与基于数据库系统的可复用构件库组织方法不同,它基于全文检索技术,其基本思想是:所有软件构件都必须辅以详细的功能或行为说明文档,说明中出现的概念和软件构件以网状链接方式互相连接。检索者在阅读文档的过程中可按照人类的联想思维方式任意跳转到包含相关概念或软件构件的文档中去。全文检索系统将用户给出的关键词与说明文档中的文字进行匹配,实现软件构件的浏览式检索。 超文本是一种非线性的网状信息组织方法,它以结点为基本单位,链作为结点之间的联想式关联,如图8.5所示。一般地,结点是一个信息块。对于可复用构件库而言,结点可以是论域的概念、功能或行为名称、构件名称等,在图形用户界面上,结点可以是字符串,也可以是图像、声音、动画等。超文本组织方式为构造可复用构件提供了友好、直观的多媒体方式。由于网状结构比较自由、松散,因此,超文本方法更容易修改可复用构件库的结构。 Windows环境下的联机帮助系统就是一种典型的超文本系统。为了构造可复用构件库的文档,首先要根据论域分析的结果,在说明文档中标识超文本结点,并在相关文档中建立链接关系。然后用类似于联机帮助系统编译器的工具对构件的说明文档进行编译,最后用相应的工具运行编译后的目标程序代码即可。 (5) 可复用构件的3C模型 可以有很多方法来描述可复用的构件,其中最理想的是由Tracz提出的3C模型:概念(Concept)、内容(Content)和上下文(Context)。 ( 概念:描述软件构件做什么。为此,需要完全地描述构件的接口和表示语义(表示在前置条件和后置条件的上下文中)。概念将传达构件的意图。 ( 内容:描述软件构件的概念如何实现。一般来讲,内容是对外来用户隐蔽的信息,是只有试图修改或测试该构件的人才需要了解的信息。 ( 上下文:将可复用的构件安置到它的应用论域中。就是说,上下文将通过定义概念的、操作的和实现的特征,使软件人员能够找到合适的构件以满足应用的需求。 为了在实际背景下使用,必须把概念、内容和上下文转换成具体的规格说明模式。关于可复用构件的分类模式,已有不少文章讨论过。所有的方法大致归为3个主要的方面:图书馆和信息科学方法、人工智能方法和超文本系统。目前,绝大多数研究都建议使用图书馆科学方法为软件构件进行分类。图8.6给出了一个使用图书馆科学索引法的分类法。“受控的索引词汇表”限制了所有可用于分类对象(或构件)的术语或语法。“不受控的索引词汇表”则对描述的自然状态不加限制。软件构件的分类模式主要有如下3类: 图8.6 源于图书馆索引方法的分类法 6. 分层式体系结构 所谓分层式体系结构,是按层次组织软件的一种软件体系结构,其中每一层软件建立在低一层的软件层上。位于同一层的软件系统或子系统具有同等的通用性,在下一层的软件比在上一层的软件通用性更强。一个层次可视为同等通用档次的一组(子)系统。 因此,在分层的体系结构中,最高层是应用层,可包容许多应用系统。次高层是构件层,可包括多个可复用构件库系统,可用于建立应用系统。应用系统建立在构件层之上,而此构件层中的许多构件库系统又是建立在更低层次的构件库系统之上。 软件的组织方式通常是指软件的静态分层结构,就像在编译连接时软件各个模块之间的分层依赖关系那样,是一种静态的关系,而不是指软件在运行时的组织和动态结构。一个系统的动态特征时由使用事例、协作、过程和结点模型来定义的。这些动态模型需要与软件的静态分层组织联合起来使用。 即使按照上述的原则,人们仍然定义出多种形式的分层式体系结构。层次的数目、层次的名称、层次的内容可随情况而定。图8.7给出一种典型的4层次体系结构。 最顶层(即最高层)是应用系统层,此层包含多个应用系统,每个应用系统向系统的用户提供一组使用事例。有的应用系统还可具有不同的版本或若干变体。应用系统可以通过其接口与其它系统操作,还可以通过低层软件提供的服务或对象(如操作系统、特定业务服务)间接地与其它系统交互操作。 次顶层(即次高层)是“特定业务”层。此层应当包括专门针对不同业务类型的一系列构件库系统。这样的构件库系统向用户提供可复用的使用事例和对象构件,用于开发应用系统,支持复用业务。特定业务层的软件建立在中间件之上。 中间件层位于次高层下面,它为次顶层的各个构件库系统提供实用软件类,以及不依赖于平台的服务。例如,在异种机型环境下的分布式对象计算等等。此层经常包括:图形用户界面构筑者使用的构件库系统、与数据库管理系统(DBMS)的接口、不依赖平台的操作系统服务、对象请求代理(ORBs)、对象链接和嵌入OLE构件,如电子表格和框图编辑器。这些软件主要提供给应用软件和构件开发人员使用,使得他们能够专注于业务构件和应用系统的构筑。 最低层是系统软件层,此层包括计算和网络等基础设施软件,如操作系统、专用的硬件接口软件等。 目前出现了一些专用操作系统,其本身就提供了不依赖于平台的服务,因此,在依稀结构的第三层和第四层之间,有时界限会变得模糊不清。例如Java就是这种情况。它是一种语言,故它应该位于系统软件层。但还可以把Java看作是组织分布对象的一个重要部分,通过Java可将对象移到不同的机器上,从而改变客户机―服务器系统的应用划分。从另一个角度来看,Java的一个重要部分又属于中间件层,至少位于中间件层的许多软件都是用Java语言编写的。 为了确保分层式系统可管理,规定在一个系统内,不能从低层复用高层的构件。一个分层式系统有两维:水平方向是在同层次内的相互引用的多个系统,垂直方向表达了跨层次的静态的依赖关系。 7. 软件构件的复用 (1) 检索与提取构件 可复用构件库的检索方法与库的组织方式密切相关。 ① 基于关键词的检索 这种检索方法的基本思想是:系统(CASE工具)在图形用户界面上将可复用构件库的关键词树直观地展示给用户,用户通过在树上的逐级浏览寻找需要的关键词并提取相应的构件。当然,用户也可以直接给出关键词(其中可含有通配符),由系统自动地给出合适的候选构件清单。 这种方法的优点是简单,易于实现。 ② 多面检索 这种检索方法基于多面分类法。步骤如下: ( 构造查询:用户提供待查构件在每个“面”上的特征,生成构件描述子。此时,用户可以从可复用构件库已有的“概念”中挑选,也可以将某些特征值置为空。系统在库中检索时将忽略特征值为空的“面”。在构造查询的过程中,可以利用同义词库和概念距离图来帮助用户正确选择特征值。 ( 检索构件:实现多面分类法的CASE工具利用同义词库和概念距离图,在可复用构件库中寻找相同的或相近的构件描述子及相应的构件。 ( 对构件进行排序:按照相似程度对被检索出来的构件进行排序,还可以按照与复用有关的度量信息(如构件的复杂性、可复用性、成功复用的次数等)进行排序。 这种方法的优点是易于实现相似构件的查找。 ③ 超文本检索 这种检索方法的步骤是:用户首先给出一个或若干个关键词,系统在构件的说明文档中做精确的或模糊的语法匹配。匹配成功后,向用户提供相应的构件说明。这些构件说明是含有许多超文本结点的正文。用户在阅读这些正文时可实现多个构件说明文档之间的自由跳转,最终选择合适的构件。为了避免用户在跳转过程中迷失方向,系统可以通过图形用户界面显示浏览历史图,允许将特定画面定义为有名“书签”并可随时跳转到“书签”。此外,还可以帮助用户逆着跳转路径逐步返回。 这种方法的优点是用户界面友好。 ④ 其它检索方法 上述检索方法都是基于语法匹配,要求用户对可复用构件库中的出现的众多词汇有较全面的把握,较精确的理解。理论上,理想的检索方法是语义匹配:可复用构件库的用户以形式化的手段描述所需要的构件的功能或行为的语义,系统通过定理证明或基于知识的推理过程寻找语义上等价的或相近的构件。 (2) 理解与评价构件 准确地理解构件,对于正确地使用和修改构件,都是至关重要的。考虑到设计信息对于理解构件的必要性和构件库的用户逆向发掘设计信息的困难性,要求构件的开发过程必须遵循公共的软件工程规范,并在构件库的说明文档中全面、准确地说明下列内容: ① 构件的功能和行为; ② 相关的论域知识; ③ 可适应性约束条件和例外情况; ④ 可以预见的修改部分和修改方法。 但是,如果软件人员希望复用那些原先并非为复用而设计的构件,上述要求不能满足。此时软件人员必须借助CASE工具对待选构件进行分析。这种CASE工具对构件(包括相应的文档)进行扫描,将各类信息存入某种浏览数据库,然后回答构件用户的各种查询,进而帮助理解。例如,对于以C或C++ 源程序形式出现的构件,用户可借助于CASE工具查询标识符(包括变量、常量、宏、函数等)的定义和引用。如果源程序中以结构化注解的形式给出函数的前置条件、后置断言、约束与例外情形、算法描述,用户也可以实现对这些信息的直观浏览。 逆向工程是理解构件的另一种重要手段。通过对构件进行分析,结合论域知识,半自动地生成构件的设计信息,然后借助设计信息完成对构件的理解和修改。 对软件构件的可复用性进行评价,主要通过收集和分析构件的用户在实际复用构件的过程中所得到的各种反馈信息,按照某种论域模型来完成。这些反馈信息包括:复用成功的次数、对构件的修改工作量、构件的健壮性度量(如出错数量)、性能度量(如执行效率和资源消耗量)等。 (3) 修改构件 理想的情况是对库中的构件不做修改就可以直接用于新的软件项目。但是,在多数情况下,需要对构件做或多或少的修改以适应新的需求。为了减少修改的工作量,要求构件的开发人员尽量使构件的功能、行为、接口抽象化、通用化、参数化。这样,构件的用户可以通过对实参的选择来调整构件的功能或行为。如果这种调整仍不能使构件适应新的软件项目,用户就必须借助设计信息和说明文档来理解、修改构件。因此,与构件有关的说明文档和抽象层次更高的设计信息对于构件的修改至关重要。例如,如果需要将用C语言编写的构件(源程序代码)改写为其它语言的形式,构件的算法描述就十分必要。 有人在软件复用领域中尝试使构件的修改自动化。例如,可以利用不同数据结构(如链表和数组)之间的相似性自动修改构件外部接口中的参数类型。但是,这种自动修改方式还远远不能取代人工修改方式。 (4) 构件的合成 构件合成是指将可复用构件库中的构件(经适当修改后)相互连接,或将它们与当前软件项目中的软件元素相连接以构成最终的目标系统。构件合成技术大致可分为基于功能的、基于数据的和面向对象的合成技术。下面简单介绍前两种。 ① 基于功能的合成技术 基于功能的合成技术采用子程序调用和参数传递的方式将构件结合起来。它要求在库中的构件必须以标准子程序(标准过程或函数)的形式出现,并且接口说明必须准确、清楚。当使用这种合成技术进行软件开发时,必须开发人员必须对目标软件系统进行自顶向下的功能分解,将系统分解为高内聚、低耦合的功能模块,然后根据各模块的功能需求提取构件,对它们进行适应性修改后,再纳入到上述功能分解的层次框架中。 ② 基于数据的合成技术 基于数据的合成技术首先根据当前应用问题的核心数据结构设计出一个框架,然后根据框架中各结点的需求提取构件并进行适应性修改,再把它们逐个分配给框架中的适当位置。此后,构件的合成方式仍然是传统的子程序调用与参数传递。这种合成技术也要求库中的构件以子程序的形式出现,但它所依赖的软件设计方法不再是功能分解,而是面向数据结构的设计方法,如Jackson系统开发方法。 8. 面向对象的软件复用技术 由于封装和继承的特性,面向对象方法比其它软件开发方法更适合支持软件复用。封装意味着可以将表示构件的类看作黑盒子。使用它们时,只需了解其外部接口,即了解它能够响应哪些消息,相应的对象行为是什么。继承是指在定义新的子类时可利用库中已有的父类的属性和操作。当然,子类也可以修改父类的属性与操作,或者引进新的属性与操作。理论上构件的用户不需要了解构件的实现细节。 (1) 类库的构造 通常将面向对象的可复用构件库称为可复用类库(简称类库),因为这时所有的构件都是以类的形式出现。可复用基类的建立取决于论域分析阶段对当前应用(族)中具有一般适用性的对象和类的标识。类库的组织方式采用类的继承层次结构。这种结构与现实问题空间的实体继承关系有某种自然、直接的对应。同时,类库的文档以超文本方式组织,每个类的说明文档中都可以包含指向其它说明文档的关键词结点的链接指针。 与图形用户界面有关的一种典型的类库结构如图8.8所示。 图8.8 类库结构示例 (2) 类库的检索 一般而言,类库的组织方式直接决定检索方式。常用的类库检索方法是对类库中类的继承层次结构进行树形浏览,以及基于类库文档的超文本检索。借助于树形浏览工具,类库的用户可以从树的根部(继承层次的根类)出发,根据对可复用基类的需求,逐层确定它所属的语法和语义的范畴,然后确定最合适的基类。借助于类库的超文本文档,用户一方面可以在类库的继承层次结构中查阅各基类的属性、操作和其它特征,另一方面可按照基类之间的语义关联实现自由跳转。 需要强调的是:对类库的检索并不要求待实现的类与库中的基类完全相同或极为相似,只是希望待实现的类与基类之间存在某种自然的继承关系,或者基类能够提供属性或操作给待实现的子类选用。这与其它可复用构件库的检索截然不同。 (3) 类的合成 如果从类库中检索出来的基类能够完全满足新软件项目的需求,则可以直接复用。否则必须以类库中的基类为父类,采用构造法或子类法派生出子类。注意,面向对象的复用技术通常不允许用户修改库中的基类,要想对类库进行扩充或修改,应当调整类库的继承结构以把新的子类加入到适当的位置。 ① 构造法:为了在子类中使用库中的基类的属性和操作,可以考虑在子类中引进基类的实例作为作为子类的实例变量,然后在子类中通过实例变量来复用基类的属性或操作。构造法只用到面向对象的封装特征。 ② 子类法:与构造法完全不同,子类法把新子类直接说明为库中基类的子类。通过继承和修改基类的属性和操作来完成新子类的定义。子类法利用了面向对象的封装和继承的特性。 9. 支持软件复用的CASE工具 能否在软件开发过程中成功地使用复用技术,直接取决于CASE 工具对软件复用的支持程度。下面主要介绍复用技术的各个子任务对于CASE工具的大致需求。当然,这些CASE工具不是软件复用的必要条件,但具备这些工具能提高复用的效能。 (1) 论域分析 表8.3 论域分析的关键子任务及其支持工具 关 键 子 任 务  支 持 工 具   知识获取  专家系统建造工具   对象及其操作的标识  实体―关系图工具   抽象与关联  面向对象的开发工具   对象分类  基于语义的自动分类工具   论域语言处理  语法分析工具   (2) 构件的开发 表8.4 软件构件开发的关键子任务及其支持工具 关 键 子 任 务  支 持 工 具   提高构件独立性 依赖性分析工具(如交叉引用生成器),软件结构分析器 (如调用关系生成器、继承关系生成器)   参数化 程序设计语言中的宏替换,编译器中的预处理器,类属 机制(如Ada中的Generic)   抽象与特殊化 面向对象语言的继承机制   构件的扩充 (增加功能,扩大适用范围) 面向对象的语言机制,支持同一软件元素以多个版本不 断演化的配置管理工具   测试与认证 测试覆盖面分析工具   形式验证 定理证明工具   构件质量评估 软件质量的度量与分析工具   构件的分类 语义近似性分析工具,基于规则的专家系统   (3) 构件库的组织与检索 表8.5 软件构件库组织与检索的关键子任务及其支持工具 关 键 子 任 务  支 持 工 具   可复用构件库的组织与存储 关系数据库或面向对象数据库管理系统,类库   浏览 超文本浏览工具   检索 自然语言的语法分析与语义理解工具   结构化查询 关系数据库管理系统   基于语义的检索 定理证明工具(用于语义匹配)   (4) 构件的合成 表8.6 软件构件库合成的关键子任务及其支持工具 关 键 子 任 务  支 持 工 具   构件的修改 源程序代码的比较工具   构件的实例化 宏扩展工具,模板程序的实例数据生成工具   修改后构件的正确性验证 用于支持在软件维护阶段修改软件元素的CASE工具   将构件合成到目标软件系统 编译器,连接器以及集成化CASE环境中的其它合成机制   三、例题分析 【例1】实施软件复用的目的是要使软件开发工作进行得( A )。软件复用的实际效益除了( B )之外,在企业的经营管理方面也可望达到理想的效益。 新的应用软件开发技术和工具是以( C )作为关键,复用大粒度的( D ),为的是快速开发应用软件。这些新技术包括微软的( E )、( F )、( G ),SUN公司的Java,OMG公司的CORBA、IDL等。 供选择的答案: A. ① 更简捷 ② 更方便 ③ 更快、更好、更省 ④ 更丰富 B. ① 复用率 ② 功能扩充 ③ 效率 ④ 空间利用率 C, D. ① 软件 ② 固件 ③ 构件 ④ 属性 ⑤ 对象 ⑥ 事物 ⑦ 数据 ⑧ 代码 E(G. ① office ② Visual Basic ③ Active X ④ Photoshop ⑤ OLE ⑥ Fortran ⑦ COBOL ⑧ Delphi 答案:A. ③, B. ①, C. ③, D. ⑤, E. ②, F. ③, G. ⑤。其中,E、F、G的答案顺序可互换。 分析:实施软件复用的目的是要使软件开发工作进行得是更快、更好、更省。“更快”是指在市场竞争环境中,软件开发工作能满足市场上时间方面的要求(即在提供软件产品的时间方面能赛过竞争对手);“更好”是指开发出来的软件在未来的运行中失效可能性小;“更省”是指在开发和维护期间所花费的开销少。 日美一些大公司的资料表明,软件复用率最高可望达到90 %,而且软件复用使得企业在及时满足市场、软件质量、软件开发和维护费用等方面都得到显著的改进。 除了复用率之外,在企业的经营管理方面也可望达到理想的效益。例如,上市时间可缩短2 ( 5倍;软件产品的缺陷密度可减少5 ( 10倍;软件产品的维护费用可减少5 ( 10倍;软件开发总费用可减少15% ( 75%,其中,75%是针对长期项目,包括开发可复用构件及支持复用的负担。 新的应用软件开发技术和工具是以“构件”作为关键,复用大粒度的“对象”,为的是快速开发应用软件。这些新技术包括微软的Visual Basic、Active X、OLE(对象链接与嵌入),SUN公司的Java,OMG公司的CORBA(公用对象请求代理程序体系结构)、IDL(接口定义语言)等。非面向对象语言(如COBOL和Fortran)在复用实践中已经器的相当的成功。这些非面向对象程序设计语言构件技术的成功实践说明了:实现软件复用并不限于面向对象语言构件或类库。 【例2】以往的软件工程技术不能满足复用的需要,体现在工程、( A )、( B )、经营业务等4个方面。“工程”指软件开发工程,表现在缺乏( C )手段,缺乏( D )构件,缺乏对潜在可复用的( E ),缺乏实施复用的工具。 供选择的答案: A, B. ① 需求 ② 过程 ③ 环境 ④ 组织管理 C ( E. ① 复用 ② 可靠性 ③ 灵活性 ④ 界定 ⑤ 工具 ⑥ 互连性 答案:A. ②, B. ④, C. ④, D. ①, E. ③。其中,A、B的答案的顺序可互换。 分析:以往的软件工程技术不能满足复用的需要,体现在工程、过程、组织管理、经营业务等4个方面。这里所说的“工程”是指软件开发工程,其技术和方法面对复用的需要已显得低效,主要表现在: ( 缺乏界定手段:为了软件复用,需要循软件开发流程的各个阶段,通过分析它们的描述模型,明确界定出潜在可复用的部分,被界定出的部分,可能是可被复用的部分,也可能是可被可复用构件代用的部分。而以往的软件工程缺乏这种界定手段。 ( 缺乏可复用的构件:者反映在许多方面。例如,不能有效地挑选出可复用构件并对它们进行强化;缺乏对构件打包、文档化、分类、界定的技术;缺乏有效方法进行(构件)库的设计和实现;缺乏良好的构件库存取方法。 ( 缺乏对潜在可复用构件的灵活性:如果一个构件很死板,那么它被复用的机会就很少。而过去的软件工程方法在设计灵活的、分层的软件体系结构方面一直没有不成熟的办法。过去的方法是对构件进行调节使之满足新的需求,或者使对新的体系结构进行限制。 ( 缺乏实施复用的工具:为了实施复用,需要一系列新的工具,并把它们集成到面向复用的软件工程环境中去。而过去的工程缺乏这方面的工具。 【例3】论域工程过程要在选定的应用论域中界定出( A )和( B ),要为多个应用和构件定义一个( C ),并开发一系列可适度扩展的( D )。创建可复用构件既困难又昂贵。所以,应当帮助软件人员进行界定工作,以及按重要性对各项( E )进行优先性排队。在一定程度上,这项工作要依赖于( F )。 供选择的答案: A, B, E, F:① 共性 ② 特性 ③ 可变性 ④ 属性 ⑤ 灵活性 ⑥ 可靠性 ⑦ 健壮性 ⑧ 适用性 C, D: ① 固件 ② 构件 ③ 体系结构 ④ 组件 ⑤ 总体框图 ⑥ 数据结构 答案:A. ①, B. ③, C. ③, D. ②, E. ②, F. ⑥。其中,A、B的答案顺序可互换。 分析:论域工程过程要在选定的应用论域中界定出共性和可变性,要为多个应用和构件定义一个体系结构,并开发一系列可适度扩展的构件。创建可复用构件既困难又昂贵。所以,应当帮助软件人员进行界定工作,以及按重要性对各项“特性”进行优先性排队。在一定程度上,这项工作要依赖于预测的可靠性(预测需要哪些应用层的可靠性和构件层的可靠性),这也关系到我们要冒多大的风险。 【例4】软件体系设计的一个中心问题是能否( A ),以及采用何种软件体系结构风格。有原则地使用体系结构风格可带来一些实际的好处: (1) 它促进了对设计的( B ); (2) 它可以带来显著的( C )(体系结构风格的不变部分使它们可以共享同一个实现代码); (3) 只要系统是使用常用的、规范的方法组织起来的,就可以让其它设计者很容易地理解软件的体系结构; (4) 对标准或规范风格的使用也支持了( D ),例如像CORBA这样的面向对象的架构和基于事件机制的工具的集成; (5) 在限制了设计空间的情况下体系结构风格通常允许进行特殊的与风格有关的分析; (6) 通常可以对特定的风格提供( E )手段。 供选择的答案: A ( C. ① 使用特定的体系模式 ② 使用重复的体系模式 ③ 复用 ④ 专用 ⑤ 代码复用 ⑥ 结构复用 D ( E. ① 可视化 ② 构件 ③ 互操作性 ④ 可移植性 ⑤ 可调度性 ⑥ 框架 答案:A. ②, B. ③, C. ⑤, D. ③, E. ①。 分析:软件体系设计的一个中心问题是能否使用重复的体系模式,以及采用何种软件体系结构风格。例如可以采用通用的基于层次或数据流的系统体系结构,或者采用特殊的系统组织(如经典的编译器分解方式),OSI七层协议,MVC用户界面语义图等。有原则地使用体系结构风格可带来一系列实际的好处。 (1) 它促进了对设计的复用。一些经过实践证实的解决方案可以拿来可靠地解决新问题。 (2) 它可以带来显著的代码复用。体系结构风格的不变部分使它们可以共享同一个实现代码。 (3) 只要系统是使用常用的、规范的方法组织起来的,就可以让其它设计者很容易地理解软件的体系结构。例如,如果某人把系统描述为“客户机∕服务器”模式,则不必给出细节,人们立刻就会明白它们是如何一部分一部分地组织起来,并在脑海中清晰地得到这个图像。 (4) 对标准或规范风格的使用也支持了互操作性,例如像CORBA这样的面向对象的架构和基于事件机制的工具的集成; (5) 在限制了设计空间的情况下,体系结构风格通常允许进行特殊的与风格有关的分析。例如,分析管道过滤器系统的可调度性(吞吐量、延时、死锁的解决)是可行的,但对于任意的、或用其它方法构造的架构来说,这种分析可能毫无意义。 (6) 通常可以对特定的风格提供可视化的手段。例如,可以对与客户的专业领域有关的设计作出图解或文字说明。 对于应用软件体系结构风格来说,由于视点的不同,软件人员有很大的选择空间。要为系统选择或设计某一个体系结构风格,必须根据特定项目的具体特点,进行分析比较后再确定。体系结构风格的使用几乎完全是特化的。 【例5】分层系统采用层次化的组织方法,每一层向其( A )提供服务,并利用( B )的服务。在一些分层系统中,( C )全部被隐藏起来,只有( D )和一部分精心选择的功能可以被系统外部看到。在这种系统中,( E )是实现在层次结构中的一些虚拟机,( F )是层次与层次之间交互的协议,( G )包括对层次之间交互的限制。分层系统中有许多可取的属性。首先,它支持( H )的系统设计,这使得设计者可以把一个复杂的系统按递增的步骤分解开来;其次,它支持( I ),像管道结构的系统一样,因为每一层至多和相邻的上下层交互,因此,功能的改变最多只影响相邻的上下层。另外,它能支持( J ),和抽象数据类型一样,只要提供的服务接口定义不变,同一层的不同实现可以交换使用。 供选择的答案: A ( D. ① 下层 ② 内部层次 ③ 外部层次 ④ 上层 ⑤ 中间件 ⑥ 接口 E ( G. ① 接口定义 ② 软件部件 ③ 连接 ④ 拓扑约束 ⑤ 规范定义 ⑥ 推理机制 ⑦ 系统结构 H ( J. ① 基于抽象程度递增 ② 基于具体细节递增 ③ 复用 ④ 可视化 ⑤ 互操作 ⑥ 功能增强 ⑦ 效率提高 ⑧ 结构化 答案:A. ④, B. ①, C. ②, D. ③, E. ②, F. ③, G. ④, H. ①, I. ⑥, J. ③。 分析:对于分层系统: (1) 基本结构:分层系统采用层次化的组织方法,每一层向其上层提供服务,并利用其下层的服务。在一些分层系统中,内部层次全部被隐藏起来,只有外部层次及一部分精心选择的功能可以被系统外部所见。在这种系统中,软件部件是实现在层次结构中的一些虚拟机,连接是层次与层次之间交互的协议,拓扑约束包括对层次之间交互的限制。如图所示。 (2) 应用:这种系统最广泛的应用是分层通信协议。在这一应用论域中,每一层提供一级抽象的功能,作为上层通信的基础。较低的层次定义低层的交互,最低层通常只定义硬件物理连接。其它应用论域有数据库系统、操作系统等。 (3) 分层系统中有许多可取的属性。首先,它支持基于抽象程度递增的系统设计,这使得设计者可以把一个复杂的系统按递增的步骤分解开来;其次,它支持功能增强,像管道结构的系统一样,因为每一层至多和相邻的上下层交互,因此,功能的改变最多只影响相邻的上下层。另外,它能支持复用,和抽象数据类型一样,只要提供的服务接口定义不变,同一层的不同实现可以交换使用。这样,就可以定义一组标准的接口,并允许有各种不同的实现方法(典型的例子是ISO OSI参考模型和某些X Windows的系统协议)。 【例6】软件复用可分为以下三个层次: ( A ),例如软件工程知识的复用。 ( B ),例如面向对象方法或国家制定的软件开发规范的复用。 软件成分的复用。软件成分的复用又可进一步划分为( C ),如剪贴;( D ),如复用设计模型;( E ),更高级别复用。 为了研究软件复用程度与软件生产率之间的关系,我们引进:生产率P = ( F )和复用率R = ( G )的公式,以及两者之间的关系P = ( H )。其中,用Lt代表程序总长度,Ln和Lr分别为新编代码和复用代码的长度。令Et、En和Er分别代表开发该程序的总工作量、新编程序的工作量和复用已有软件构件的工作量,Cn和Cr分别代表开发新代码和复用已有软件构件的生产率。 供选择的答案: A ( E. ① 知识复用 ② 分析结果复用 ③ 代码复用 ④ 方法与标准复用 ⑤ 设计结果复用 ⑥ 软件成分复用 F ( H. ① ② ③ ④ ⑤ ⑥ ⑦ 答案:A. ①, B. ④, C. ③, D. ⑤, E. ②, F. ④, G. ②, H. ③。 分析:广义来讲,软件复用可分为以下三个层次: (1) 知识复用(如软件工程知识的复用); (2) 方法和标准的复用(如面向对象方法或国家制定的软件开发规范的复用); (3) 软件成分的复用。软件成分的复用又可进一步划分为三个级别:① 代码复用(源代码剪贴、源代码包含、继承);② 设计结果复用;③ 分析结果复用(这是一种更高级别的复用,即复用某个系统的分析模型)。 为实现软件复用需要付出额外代价,如投资、时间和可复用构件库。 即使不考虑上述的额外代价,软件复用也不是必然能提高软件生产率。为研究软件复用程度与软件生产率的关系,我们首先引入下列两个量: 生产率P = 程序总长度∕开发该程序所用人时数 复用率R = 复用代码长度∕程序总长度 令Lt为程序总长度(目标代码条数),Ln和Lr分别为新编代码和复用代码的长度(都用目标代码条数来度量)。再令Et、En和Er分别代表开发该程序的总工作量、新编程序的工作量和复用已有软件构件的工作量,则有以下等式成立: Lt = Ln + Lr, Et = En + Er, P = Lt∕Et, R = Lr∕Lt. 此外,用符号Cn和Cr分别代表开发新代码和复用已有软件构件的生产率,则有: Cn = Ln∕En, Cr = Lr∕Er. 从上述6个等式出发,可以推导出下列的生产率与复用率之间的关系: 从上式可知,复用率R越高,生产率不一定就越高。只有当软件开发人员使用已有的软件构件构造应用系统时,其工作效率比重新从底层编写程序的效率高时,复用率的提高才会导致生产率提高。可见,通过软件复用来提高软件生产率,并不是一件轻而易举的事情。构件的实用程度和使用方便程度,以及软件人员的素质、开发环境等因素,都直接影响软件复用的效果。 四、习题 【8-1】软件复用的含义是什么?软件复用的范围有哪些方面? 【8-2】简述软件复用的大致过程。说明在此过程中每个步骤需采用的关键步骤。 【8-3】回答下列问题。 (1) 比较横向复用和纵向复用的异同及优劣。 (2) 假定有一个结构形如图8.3所示的构件库,基于该构件库的软件复用属于横向复用还是纵向复用?为什么? 【8-4】当今大多数软件复用过程中,都涉及创建过程的一个重要活动,即界定潜在的可复用的资源。在这个活动中需要一整套的界定方法,并需要一个能确保可复用资源被复用的体系结构。这个活动就叫做( A )。而应用软件的开发过程或复用过程则称为( B )。系统地软件复用的实质是:( C )先投资,即界定并仔细地创建出可复用的资源,从而可以使得( D )能够又快又省地开发应用软件。 供选择的答案: A, B. ① 应用系统工程 ② 软件工程 ③ 论域工程 ④ 需求工程 C, D. ① 用户 ② 创建者 ③ 复用者 ④ 投资者 ⑤ 管理者 【8-5】所谓一个“构件”,可以是一个类型、类或其它的工作成品。对于构件,应当按可复用的要求( A )、( B )、打包、编写文档。构件是( C ),并具有相当稳定的公开的( D )。这里的构件是基于( E )技术的。( E )技术中的封装、多态等特性,可简化构件的开发工作。而( E )技术中的( F )机制则有使开发简化、维护复杂的两面性。 供选择的答案: A, B. ① 实现 ② 运行 ③ 设计 ④ 计划 C, D. ① 外联的 ② 内聚的 ③ 公开的 ④ 私有的 ⑤ 外设 ⑥ 接口 ⑦ 输出 E, F. ① 面向数据 ② 面向对象 ③ 封装 ④ 继承 ⑤ 复用 【8-6】软件开发人员必须用各种抽象化手段来开发代码级构件。典型的抽象方法有3种。( A )、( B )、( C )。( A )使构件的( D )仅由接口说明确定,而把实现细节对构件的使用者隐藏起来;( B )在( A )的基础上进一步隐藏除接口参数外的所有数据。面向对象程序设计语言中的“类”是一种典型的基于( B )的构件。( C )则在( B )的基础上进一步实现在同一构件上并发执行的多个( E )的无关性。构件提供端口,以便为多个( F )同时访问构件中的资源进行( G )控制。 供选择的答案: A ( B. ① 数据抽象 ② 需求抽象 ③ 设计抽象 ④ 过程抽象 ⑤ 功能抽象 ⑥ 实例抽象 D ( G. ① 异步 ② 程序 ③ 线程 ④ 用户 ⑤ 功能 ⑥ 同步 【8-7】所谓分层式体系结构是按层组织的软件的一种软件体系结构,其中,每一层的软件建立在低一层的软件层上。低层软件比高层软件更具( A )。右图是一种4层次的分层体系结构,请选择B、C、D、E。 供选择的答案: A. ① 高效性 ② 通用性 ③ 可靠性 ④ 保密性 B ( E. ① 系统软件 ② 特定业务 ③ 中间件 ④ 应用软件 ⑤ 软件平台 【8-8】回答下列问题。 (1) 简述关键词分类法、多面分类法和超文本分类法等组织方法的概要。 (2) 简述相应的检索方法。 【8-9】可以有很多方法来描述可复用的构件,其中最理想的是由Tracz提出的3C模型。3C是指( A )、( B )和( C )。( A )描述构件做什么。为此,需要完全地描述构件的( D )和表示( E )。( B )描述构件的( F )如何实现。一般来讲,( B )是对外来用户( G )的信息,是只有试图修改或测试该构件的人才需要了解的信息。( C )将通过定义概念的、操作的和实现的特征,使用户能够找到合适的构件以满足应用的需求。 供选择的答案: A ( C. ① 包容(container) ② 上下文(context) ③ 代价(cost) ④ 控制(control) ⑤ 概念(concept) ⑥ 内容(content) D ( C. ① 概念 ② 接口 ③ 公开 ④ 服务 ⑤ 语义 ⑥ 语法 ⑦ 隐藏 ⑧ 结构 【8-10】试简述基于软件复用的软件项目管理机构的组织和工作职责。 五、习题解答 【8-1】软件复用就是指利用某些早先开发的对建立新软件系统有用的软件元素来生产新系统。软件复用的范围有以下十个方面: ① 项目计划:软件项目计划的基本结构和许多内容都可以跨项目复用。 ② 成本估计:由于不同项目中常包含类似的功能,所以有可能在极少修改或不修改的情况下,复用对该功能的成本估计。 ③ 体系结构:即便应用论域千差万别,但程序和数据体系结构大同小异。因此,可以创建一组类属的体系结构模板,将这些模板作为可复用的涉及框架。 ④ 需求模型和规格说明:类和对象的模型和规格说明显然可以复用。此外,用传统软件工程方法开发的分析模型也可以复用。 ⑤ 设计:用传统方法开发的体系结构、数据、接口和过程化设计,以及用面向对象方法开发的系统和对象的设计都可以复用。 ⑥ 源程序代码:验证过的程序构件可以拿来复用的。 ⑦ 用户文档和技术文档:即便特定的应用不同,但也经常有可能复用用户文档和技术文档中的大部分内容。 ⑧ 用户界面:这可能是最广泛被复用的软件元素。如经常复用GUI的软件构件。 ⑨ 数据结构:经常被复用的数据结构包括:内部表、列表和记录结构,以及文件和完整的数据库。 ⑩ 测试用例:只要将设计或代码构件定义成可复用构件,相关的测试用例就应当成为这些构件的“从属品”。 【8-2】软件复用过程如图所示。主要关键点在于论域分析:根据应用论域的特征和相似性,预测构件的可复用性。一旦根据论域分析确认了构件的可复用价值,即可进行构件的开发,并对具有可复用价值的构件做一般化处理,使它们能够适应新的类似的应用论域。然后将软件构件和它们的文档存入可复用构件库,成为可供未来开发项目使用的可复用资源。这些步骤构成构件的构造活动。 随着可复用构件的不断丰富,可复用构件库的规模会不断扩大,必须考虑如何组织库的结构以保持较高的检索效率。可供选择的软件构件从库中被检索出来之后,用户还必须理解它的功能或行为,以判定它是否真正适合于当前的应用。必要时,可考虑对某个与期望的功能或行为匹配程度最好的可复用构件进行少量修改,甚至可将修改后的构件再加到可复用构件库中。 软件复用的过程可借助计算机的帮助。支持软件复用的CASE 工具的主要工作是:用某种组织形式实现可复用构件的存储,提供友好的人机界面,帮助用户浏览、检索和修改可复用构件库,对用户感兴趣的软件构件进行解释。事实上,几乎所有的软件复用活动都是在CASE工具的帮助下进行的。下面列出软件复用各个步骤中的关键技术。 论域分析  构件开发 构件库的组织与检索  构件合成  知识获取 提高构件独立性 构件库的组织与存储 构件修改  对象及其操作标识 参数化 浏览 构件实例化  抽象与关联 抽象与特殊化 检索 修改后构件正确性验证  对象分类 构件的扩充 结构化查询 将构件合成到目标软件系统  论域语言处理 测试与认证 基于语义的检索    形式验证     构件质量评估     构件分类    【8-3】(1) 软件复用可以区分为横向复用和纵向复用。横向复用是复用不同应用论域中的软件元素,例如数据结构、排序算法、人机界面构件等。标准函数库是一种典型的原始的横向复用机制。纵向复用是在一类具有较多公共性的应用论域之间复用软件构件。 横向复用是在几个截然不同的应用论域之间进行软件复用,可复用的资源有限,潜力不大。纵向复用的应用范围较大,从系统软件到特定论域的软件及应用软件,还有软件工程过程方面,许多计算机软件厂商开发了大量可复用的构件或软件包,在软件工程实践中取得显著的效益,因此受到广泛关注。 (2) 图8.3 是关键词分类结构的示例,它是横向复用的典型例子,用户界面所涉及的技术可用于各个不同应用论域的软件中。 【8-4】A. ③, B. ①, C. ②, D. ③ 当今大多数软件复用过程中,都涉及创建过程的一个重要活动,即界定潜在的可复用的资源。在这个活动中需要一整套的界定方法,并需要一个能确保可复用资源被复用的体系结构。这个活动就叫做论域工程。而应用软件的开发过程或复用过程则称为应用系统工程。系统地软件复用的实质是:创建者先投资,即界定并仔细地创建出可复用的资源,从而可以使得复用者能够又快又省地开发应用软件。 【8-5】A. ③, B. ①, C. ②, D. ⑥, E. ②, F. ④。 所谓一个构件,可以是一个类型、类或其它的工作成品。对于构件应当按可复用的要求设计、实现、打包、编写文档。构件是内聚性很强的,并具有相当稳定的公开的接口。这里的构件是基于面向对象技术的。面向对象技术中的封装、多态等特性,可简化构件的开发工作。而面向对象技术中的继承机制则有两面性,一方面可以简化开发工作,另一方面使构件的维护变得很复杂。 【8-6】A. ⑤, B. ①, C. ④, D. ⑤, E. ③, F. ④, G. ⑥。 软件开发人员必须用各种抽象化手段来开发代码级构件。典型的抽象方法有3种。功能抽象、数据抽象和过程抽象。功能抽象要求构件的功能仅由接口说明中的输入―关系确定,把构件的实现细节对构件的使用者隐藏起来。数据抽象则在功能抽象的基础上进一步隐藏除接口参数外的所有数据。构件的功能或行为可以由输入参数和构件自身记忆的内部状态决定。面向对象程序设计语言中的“类”是一种典型的基于数据抽象的构件。而过程抽象在数据抽象的基础上进一步实现在同一构件上并发执行的多个线程的无关性。构件提供端口,以便为多个用户同时访问软件构件中的资源进行同步控制。访问请求首先进入等待队列,构件就绪后,从队列中取出请求逐个执行。使用构件的多个线程之间通过全局共享数据或消息传递进行信息交换。构件的设计必须保证构件接口元素的功能和行为在语义上的正确性,不管各线程操作序列之间的相对时序如何变化。 【8-7】A. ②, B. ④, C. ②, D. ③, E. ①。 在分层式体系结构中,位于同一层上的各个软件系统或子系统具有同等的通用性。每一层的软件建立在低一层的软件层上。低层软件比高层软件更具通用性。最高层是应用软件层,可包容许多应用系统。次高层是特定业务层,包括针对不同业务类型的许多构件库。中间件层位于特定业务层下面,它为其上层提供各种实用软件类,最低层是系统软件层,它包含许多基础设施软件,如操作系统、网络接口软件等。这种4层次的分层体系结构见图。 【8-8】(1) 软件构件的分类方法和相应的构件库结构对构件的检索和理解有极为深刻的影响,就是说,可复用构件库的组织应当便于构件的存储和检索。 ① 关键词分类法。此方法的基本思想是:根据论域分析的结果,将应用论域(族)的概念按照从抽象到具体的顺序,逐步分解树形结构或有向无回路图结构。每个概念用一个描述性的关键词表示。不可再分解的原子层的包含隶属于它的某些软件构件。下图给出了可复用构件库的关键词分类结构,它支持图形用户界面设计。 当加入新的构件时,库管理员应对构件的功能或行为进行分析,浏览上述关键词分类结构,将构件置于最合适的原子层关键词下。如果无法找到构件应从属的关键词,可以扩充关键词分类结构,引进新的关键词。但必须保证新关键词有相应的论域分析的结果作为支持。 ② 多面分类法。此方法由3部分构成:多面分类机制、同义词库和概念距离图。 ⅰ)多面分类机制:分析论域范围并定义若干用于描述一个构件特征的“面”,每个“面”包含若干“概念”,它们表述构件在“面”上的基本特征。这些特征根据它们的重要性排队。“面”可以描述构件执行的功能、被操作的数据、构件应用的上下文以及任何其它特征。描述某一构件的“面”的集合称为面描述子。 ⅱ)同义词库:意义相同或相近的若干词汇组成同义词库。所有词汇按照隶属于“面”的“概念”分组,在任一时刻点,每个“概念”可用组内的某一同义词汇作为标识载体。 ⅲ)概念距离图:用于度量每个“面”中“概念”的相似性程度。属于每个“面”的一般化概念与其中的两个或多个“概念”以加权边相连接,两个“概念”的相似性由它们之间的最短加权路径上的加权距离确定,附加于边上的权值体现了“概念”之间的差异程度。 采用多面分类法进行可复用构件库的组织,必须在存储软件构件的同时,表示并存储多面分类机制、同义词库和概念距离图。多面分类法的所有语法构件(“面”、“概念”、同义词、一般化概念、差异性权值)均取材于论域分析的结果。当需要在可复用构件库中加入新的构件时,库管理源必须对构件的功能、行为进行深入分析,利用现有的多面分类结构确定构件的描述子,对每个“面”选取合适的“概念”作为特征描述。必要时可以考虑增加新的“概念”,此时必须根据新“概念”完善同义词库和概念距离图。 ③ 超文本组织法。此方法的基本思想是:所有构件都必须辅以详细的功能或行为说明文档,说明中出现的概念和构件以网状链接方式互相连接。检索者在阅读文档的过程中可任意跳转到包含相关概念或软件构件的文档中去。全文检索系统将用户给出的关键词与说明文档中的文字进行匹配,实现软件构件的浏览式检索。 超文本方法以结点为基本单位,链作为结点之间的联想式关联。一般地,结点是一个信息块。对于可复用构件库而言,结点可以是论域的概念、功能或行为名称、构件名称等,在图形用户界面上,结点可以是字符串,也可以是图像、声音、动画等。 (2) 可复用构件库的检索方法与库的组织方式密切相关。 ① 基于关键词的检索:这种检索方法的基本思想是:系统(CASE工具)在图形用户界面上将可复用构件库的关键词树直观地展示给用户,用户通过在树上的逐级浏览寻找需要的关键词并提取相应的构件。当然,用户也可以直接给出关键词(其中可含有通配符),由系统自动地给出合适的候选构件清单。这种方法的优点是简单,易于实现。缺点是对库的浏览容易使用户迷失方向。 ② 多面检索:这种检索方法基于多面分类法。步骤如下: ( 构造查询:用户提供待查构件在每个“面”上的特征,生成构件描述子。此时,用户可以从可复用构件库已有的“概念”中挑选,也可以将某些特征值置为空。系统在库中检索时将忽略特征值为空的“面”。在构造查询的过程中,可以利用同义词库和概念距离图来帮助用户正确选择特征值。 ( 检索构件:实现多面分类法的CASE工具利用同义词库和概念距离图,在可复用构件库中寻找相同的或相近的构件描述子及相应的构件。 ( 对构件进行排序:按照相似程度对被检索出来的构件进行排序,还可以按照与复用有关的度量信息(如构件的复杂性、可复用性、成功复用的次数等)进行排序。 这种方法的优点是易于实现相似构件的查找,但用户构造查询比较麻烦。 ③ 超文本检索:这种检索方法的步骤是:用户首先给出一个或若干个关键词,系统在构件的说明文档中做精确的或模糊的语法匹配。匹配成功后,向用户提供相应的构件说明。这些构件说明是含有许多超文本结点的正文。用户在阅读这些正文时可实现多个构件说明文档之间的自由跳转,最终选择合适的构件。为了避免用户在跳转过程中迷失方向,系统可以通过图形用户界面显示浏览历史图,允许将特定画面定义为有名“书签”并可随时跳转到“书签”。此外,还可以帮助用户逆着跳转路径逐步返回。 这种方法的优点是用户界面友好,但在某些情况下用户难以在超文本浏览过程中正确选择软件构件。 ④ 其它检索方法:上述检索方法都是基于语法匹配,要求用户对可复用构件库中的出现的众多词汇有较全面的把握,较精确的理解。理论上,理想的检索方法是语义匹配:可复用构件库的用户以形式化的手段描述所需要的构件的功能或行为的语义,系统通过定理证明或基于知识的推理过程寻找语义上等价的或相近的构件。但这种基于语义的检索方法涉及许多人工智能的难题,目前难于支持大型构件库的工程实现。 【8-9】A. ⑤, B. ⑥, C. ②, D. ②, E. ⑤, F. ①, G. ⑦。 可以有很多方法来描述可复用的构件,其中最理想的是由Tracz提出的3C模型。3C是指概念(concept)、内容(content)和上下文(context)。概念描述软件构件做什么。为此,需要完全地描述构件的接口和表示语义(表示在前置条件和后置条件的上下文中)。概念将传达构件的意图。内容描述软件构件的概念如何实现。一般来讲,内容是对外来用户隐蔽的信息,是只有试图修改或测试该构件的人才需要了解的信息。上下文将可复用的构件安置到它的应用论域中。就是说,上下文将通过定义概念的、操作的和实现的特征,使软件人员能够找到合适的构件以满足应用的需求。 【8-10】基于复用的软件项目组织与传统的软件开发项目组织不同,它必须有两个职能,并由两个部门分别承担这两个职能。一个职能是创建,相应的部门是创建者或论域工程部门;另一个职能是复用,相应的部门是复用者或应用工程部门。而具有复用经验的单位,往往还需要第三个职能,即支持,相应的部门是支持者或支持部门。创建、复用和支持这三个平行的部门之上,还有一个高层经理,他关注的是总目标。 ① 复用者负责传统的软件开发任务。同时,在各开发阶段,软件人员可查询构件库,从中检索可复用构件,进行适应性修改后将其合成到当前的目标软件中来。此外,对于同类(或同族)应用的首次开发,复用者还需在做需求分析之前进行论域分析,以便为系统地构造软件构件提供依据。 ② 创建者负责从复用者手中接受构件的设计规格说明,进行构件的设计、实现和质量控制,重点考虑因素是构件的可复用性。在构件库的积累初期,开发可复用构件的工作量较大,需要设立专门的软件构件开发组。但随着构件库的不断丰富,可以考虑将构件开发组并入系统开发组。 ③ 高层经理负责管理、组织和协调各类软件复用活动,并处理所有有关复用的事务性工作。所有下属的创建、复用和支持部门都应定期向他报告各自复用活动的当前状况,高层经理根据这些状况制定或调整复用计划,实施奖励,以调动开发人员的复用积极性。此外,他还应根据整体复用情况,向项目管理人员提供资源分配、进度安排等方面的决策建议。 ④ 复用支持者负责可复用构件的资格确认、质量保证、分类和存储。在可复用构件库尚未形成的初期,支持者的任务还包括开发可复用构件库和其它配套的软件复用CASE工具。此后,还可将部分力量投入应用论域中某些通用构件的开发。