全国计算机软考软件设计师考前练习及答案

更新时间:2024-04-19 01:32:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

上学吧(www.shangxueba.com)

软件自动化测试实例分析

本文由www.17tongchengliao.com提供

软件测试是对创造力和智力非常有挑战性的任务。测试一个大型软件需要的智能要超过设计这个程序的智能。软件在它发行之前应当通过彻底的测试,以保证它的可靠性和功能性,不幸的是,测试工程师要覆盖一个大型程序的所有情况会感到太麻烦和太费时。确实,软件的每个部分如能被分别测试到,同时一些指定的路径也能被测试,这对总的软件质量的保障是非常有效的。

一般的说,没有测试覆盖分析工具,软件在发行前仅有50%的源程序被测试过。在差不多有一半源代码没有被测试的情况下,大量的故障(bug)随软件一道被发行出去。在这种情况下,软件的质量、性能和功能不可能得到保障。此外,什么时候测试结束?或是否要对该程序作进一步的测试?对于测试工程师和测试管理人员来说是不知道的,通过引进测试覆盖的概念,问题就可以得到解决。

项目测试管理

1.帮助软件管理者准确地测算开发组的效率的,通过提供多层分析,包括系统/文件/类/函数的能力。

2.提供管理人员测算工程开发进度与质量分析的能力,允许在被生成的类继承图和函数调用图上,直接反显所有在规定的日期或一个小组/单个员工完成的模块,在这些图上带有覆盖在每个类/函数框上以条形图方式显示的相关质量信息,比如大小、复杂性、数据性能、代码测试覆盖等。

3. 结合软件系统质量分析能力和系统开发管理能力,提供给管理人员的带有质量数据的有关开发效率和工程开发进度信息总是即时的和精确的,因为它们是直接从源代码得来的第一 软件测试是对创造力和智力非常有挑战性的任务。测试一个大型软件需要的智能要超过设计这个程序的智能。软件在它发行之前应当通过彻底的测试,以保证它的可靠性和功能性,不幸的是,测试工程师要覆盖一个大型程序的所有情况会感到太麻烦和太费时。确实,软件的每个部分如能被分别测试到,同时一些指定的路径也能被测试,这对总的软件质量的保障是非常有效的。

一般的说,没有测试覆盖分析工具,软件在发行前仅有50%的源程序被测试过。在差不多有一半源代码没有被测试的情况下,大量的故障(bug)随软件一道被发行出去。在这种情况下,软件的质量、性能和功能不可能得到保障。此外,什么时候测试结束?或是否要对该程序作进一步的测试?对于测试工程师和测试管理人员来说是不知道的,通过引进测试覆盖的概念,问题就可以得到解决。

项目测试管理

1.帮助软件管理者准确地测算开发组的效率的,通过提供多层分析,包括系统/文件/类/函数的能力。

2.提供管理人员测算工程开发进度与质量分析的能力,允许在被生成的类继承图和函数调用图上,直接反显所有在规定的日期或一个小组/单个员工完成的模块,在这些图上带有覆盖在每个类/函数框上以条形图方式显示的相关质量信息,比如大小、复杂性、数据性能、代码测试覆盖等。

3. 结合软件系统质量分析能力和系统开发管理能力,提供给管理人员的带有质量数据

第 1 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

的有关开发效率和工程开发进度信息总是即时的和精确的,因为它们是直接从源代码得来的

第一手信息。 测试计划

软件系统不仅变得越来越庞大,但是也变得越来越复杂。复杂的代码是很难阅读、理解和修改的;必须化更多的精力去测试、维护和再测试。测试复杂性分析能帮助软件工程师容易并精确地去计划他们的测试活动。 提供系统级复杂性分析和过程级复杂性分析去精确地测量复杂性,帮助工程师更好地计划他们的测试活动。帮助工程师更好估计和使用测试复杂性度量,为满足不同层次的测试覆盖的要求,必需提供:块测试复杂性、分支测试复杂性、段测试复杂性、条件-判定测试复杂性、条件-段测试复杂性。测试复杂性的值取决于用于记录对应的测试覆盖数据的插装点的点数。 手信息。

测试用例管理

1. OO-Test提供了在国内外市场上最全面的测试覆盖分析能力,去满足不同的测试覆盖需求:

●类的测试覆盖

●函数的测试覆盖

●块的覆盖

●循环边界的覆盖

●分支的覆盖

●段的覆盖

●条件(判定)的覆盖

●段--条件的覆盖

2.TCA能确定每一个测试用例作用的范围,通过给出的测试用例就能确定被测试的类,或函数,或段。这种功能对于评估测试用例的效率,和对于修改以后指定的类或函数或段的再测试是非常有用的。

3.此外,TCA能从初始测试用例中自动地抽取最小测试用例集,并对基于类的、函数的、分支的、块的、段的覆盖等等各自分别进行划分。它可以对系统级的再测试节省大量的时间和费用。

训练新成员

1. 提供全面的静态和动态系统分析的能力,能抽取各种信息及自动生成系统文档,并且可以使被抽取的信息让新成员联机访问,大大的节省了设计人员和工程师的时间。

2.通过提供最新的和精确的各种系统概貌图和流程图(包括数据结构、类继承图、函数调用图和程序树),全局数据分析的详细报告,详细的程序逻辑图和源代码的控制流程图,帮助他们了解系统和深入地理解代码。

3.使用的GUI接口,使开发组的新成员容易自我训练;具有一个从顶层到详细的代码系统

第 2 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

动态的和图形化的表达能力;具有链接不同层次的结构图和流程图在一起的能力。

4.提供基于函数分析和流程图化的能力与基于类分析和流程图化的能力,使得一个面向对象的系统很容易被透彻地了解。

单元测试的考虑单元测试是要检验程序最小单位(模块)有无错误,它是在编码完成后,首先要施行的测试工作。一般由编码人员自己来完成,因而通常把单元测试看成是编码步骤的附属品。单元测试大多从程序的内部结构出发设计测试用例,即采用白盒测试方法,多个程序模块可以并行地独立开展测试工作。

单元测试是针对每个程序模块,解决5个方面的问题:模块接口、局部数据结构、边界条件、独立的路径和错误处理。

1.模块接口:

对模块接口的测试,是检查进出程序单元的数据流是否正确。对模块接口数据流的测试必须在任何其他测试之前进行,因为如果不能确保数据正确地输入和输出的话,所有的测试都是没有意义的。

2.局部数据结构:

在模块工作过程中,必须测试其内部的数据能否保持完整性,包括内部数据的内容、形式及相互关系不发生错误。

3.独立的路径: 在单元测试中,最主要的测试是针对路径的测试。测试用例必须能够发现由于计算错误、不正确的判定或不正常的控制流而产生的错误。

4.边界条件:

软件常常在边界地区发生问题。

5. 错误处理:

测试出错处理的要点是模块在工作中发生了错误,其中的出错处理设施是否有效。

单元测试的过程

单元测试常常和代码编写同步进行,在完成了程序编写、复查和语法正确性验证后,就应进行单元测试用例设计。 在对每个模块进行单元测试时,不能完全忽视它们和周围模块的相互联系。为模拟这一联系,在进行单元测试时,需设置若干辅助测试模块。辅助模块有两种,一种是驱动模块(driver),用以模拟被测模块的上级模块。驱动模块在单元测试中接受测试数据,把相关的数据传送给被测模块,启动被测模块,并打印出相应的结果。另一种是桩模块(stub),用以模拟被测模块工作过程中所调用的模块。桩模块由被测模块调用,它们一般只进行很少的数据处理,例如打印入口和返回,以便于检验被测模块与其下级模块的接口。

驱动器和桩都是额外的开销,这两种模块虽然在单元测试中必须编写,但却不作为最终的软件产品提供用户。如果驱动器和桩很简单的话,那么开销相对较低,然后,使用“简单”的模块是不可能进行足够的单元测试的,模块间接口的全面检验要推迟到集成测试时进行。

软件自动化测试流程

件自动化测试工具的软件测试流程,不仅仅包含完整的软件测试流程框架,同时还提供了内嵌软件测试流程的测试管理工具的支持,包括完整的测试评测方法。

第 3 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

1.软件自动化测试工具软件测试流程框架

软件自动化测试工具标准流程提供了一套完整的测试流程框架,软件测试团队可以以它为基础,根据业务发展的实际要求,定制符合团队使用的软件测试流程。 每个测试环节的具体阐述如下:

◆制定测试计划的目的是确定和描述要实施和执行的测试。这是通过生成包含测试需求和测试策略的测试计划来完成的。可以制定一个单独的测试计划,用于描述所有要实施和执行的不同测试类型,也可以为每种测试类型制定一个测试计划。 ◆设计测试的目的是确定、描述和生成测试过程和测试用例。

◆实施测试的目的是实施(记录、生成或编写)设计测试中定义的测试过程。输出工件是测试过程的计算机可读版本,称为测试脚本。

◆执行测试的目的是确保整个系统按既定意图运行。系统集成员在各迭代中编译并链接系统。每一迭代都需要测试增加的功能,并重复执行以前版本测试过的所有测试用例(回归测试)。

◆评估测试的目的是生成并交付测试评估摘要。这是通过复审并评估测试结果、确定并记录变更请求,以及计算主要测试评测方法来完成的。测试评估摘要以组织有序的格式提供测试结果和主要测试评测方法,用于评估测试对象和测试流程的质量。

2.软件自动化测试工具的评测方法

软件测试的主要评测方法包括测试覆盖和质量评测。测试覆盖是对测试完全程度的评测,它是由测试需求和测试用例的覆盖或已执行代码的覆盖表示的。质量评测是对测试对象(系统或测试的应用程序)的可靠性、稳定性以及性能的评测,它建立在对测试结果的评估和对测试过程中确定的变更请求(缺陷)分析的基础上。

2.1 覆盖评测

覆盖指标提供了“测试的完全程度如何?”这一问题的答案。最常用的覆盖评测是基于需求的测试覆盖和基于代码的测试覆盖。简而言之,测试覆盖是就需求(基于需求的)或代码的设计/实施标准(基于代码的)而言的完全程度的任意评测,如用例的核实(基于需求的)或所有代码行的执行(基于代码的)。

◆基于需求的测试覆盖

基于需求的测试覆盖在测试生命周期中要评测多次,并在测试生命周期的里程碑处提供测试覆盖的标识(如已计划的、已实施的、已执行的和成功的测试覆盖)。 测试覆盖通过以下公式计算:

测试覆盖 = T^(p,i,x,s) / RfT

其中:T是用测试过程或测试用例表示的测试 (Test) 数(已计划的、已实施的或成功的)。RfT 是测试需求 (Requirement for Test) 的总数。

◆基于代码的测试覆盖

基于代码的测试覆盖评测测试过程中已经执行的代码的多少,与之相对的是要执行的剩余代码的多少。代码覆盖可以建立在控制流(语句、分支或路径)或数据流的基础上。基于代码的测试覆盖通过以下公式计算: 测试覆盖 = I^e / TIic

其中:I^e 是用代码语句、代码分支、代码路径、数据状态判定点或数据元素名表示的已执行项目数。TIic (Total number of Items in the code) 是代码中的项目总数。

2.2 质量评测

测试覆盖的评估提供对测试完全程度的评测,对在测试过程中已发现缺陷的评估提供了最佳的软件质量指标。因为质量是软件与需求相符程度的指标,所以在这种环境中,缺陷被

第 4 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

标识为一种更改请求,该更改请求中的测试对象与需求不符。

◆缺陷报告

一般,可以将缺陷计数作为时间的函数来报告,即创建缺陷趋势图或报告;也可以将缺陷计数作为一个或多个缺陷参数的函数来报告,如作为缺陷密度报告中采用的严重性或状态参数的函数。这些分析类型分别为揭示软件可靠性的缺陷趋势或缺陷分布提供了判断依据。 ◆性能评测

评估测试对象的性能行为时,可以使用多种评测,这些评测侧重于获取与行为相关的数据,如响应时间、计时配置文件、执行流、操作可靠性和限制。这些评测主要在“评估测试”活动中进行评估,但是也可以在“执行测试”活动中使用性能评测评估测试进度和状态。 主要的性能评测包括:

◆动态监测 - 在测试执行过程中,实时获取并显示正在执行的各测试脚本的状态。 ◆响应时间/吞吐量 - 测试对象针对特定主角和/或用例的响应时间或吞吐量的评测。 ◆百分位报告 - 数据已收集值的百分位评测/计算。

◆比较报告 - 代表不同测试执行情况的两个(或多个)数据集之间的差异或趋势。

软件质量保证阅读(中英文对照)习题及答案

EXERCISES

1.Multiple choices. (1)Standard of software engineering project is defined as a of the developed product. a.the minimal level of performance b.the maximum level of performance c.robustness d.organization

(2)Quality assurance of software is .

a.an emerging subdiscipline of software engineering b.a management function c.as a verification function d.as a validation function

(3)Quality criteria suggested by Boehm and other persons include more than . a.19 b.20 c.21 d.22

(4)A quality assurance team should be . a.associated with any particular development group b.depended upon any particular development group c.responsible for reporting directly to management d.in-depended upon any particular development group

(5)The main goals of research in software engineering are . a.development of usable software standards b.development of accepted applicable standards c.development of generally applicable standards

d.to overcome the major hurdle in the path of software management

第 5 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

(6)Some software standards developed by IEEE and ANSI describe . a.configuration management plans b.documentation

c.specification practices d.software comparison

(7)The activity of quality assurance involves . a.verification activity b.program walkthroughs c.design reviews d.validation activity

(8)The process of software development includes . a.verification function b.management function c.validation function d.writing code

2.Fill in the blanks with appropriate words or phrases.

(1)The development team’s responsibility is to .

(2)Quality assurance must ensure that .

(3)Software quality assurance is now an of software engineering.

(4)Assessment of software quality still relies on .

(5)We are not yet capable of quantifying .

(6)At each stage of the software life cycle the activity of software quality assurance is clo-sely related to.

(7)One of the elusive nature of software quality is .

(8)The activity of quality assurance also involves . a.emerging subdiscipline of software engineering

b.checking the finished product and its associated documentation to be conformed with exist standards

c.most software characteristics d.validating the system

e.verification and validation activities

f.a product meets or exceeds prespecified standards g.the judgement of skilled individuals

h.to develop software standards for quality assurance

答案: 1

第 6 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

(1)a,c,d

(2)a,b (3)a,b (4)c,d

(5)a,b,c,d (6)a,b,c,d (7)b,c (8)a,c,d 2

(1)d (2)f (3)a (4)g (5)c (6)e (7)h (8)b

软件质量保证阅读(中英文对照)

SOFTWARE QUALITY ASSURANCE

The activity of software quality assurance is closely related to verification and validation activities carried out at each stage of the software life cycle[1].Indeed,in many organizations there is no distinction made between these activities.However,quality assurance and other verification and validation activities are actually quite separate,with quality assurance being a management function and verification and validation being part of the process of software development[2].

An appropriate definition of software quality assurance is provided by Bersoff(1984):Quality assurance consists of those procedures,techniques and tools applied by professionals to ensure that a product meets or exceeds prespecified standards during a products development cycle[3];and without specific prescribed standards,quality assurance entails ensuring that a product meets or exceed a minimal industrial and / or commercially acceptable level of excellence.

This definition is,of course[4],a fairly general one and it suggests that,firstly,software standards can be established and,secondly,the level of excellence of a software product can be estimated.

The development of software engineering project standards is an extremely difficult process. A standard is some abstract representation of a product which defines the minimal level of performance,robustness,organization,etc.,which the developed product must attain[5].At the time of writing,some software standards have been developed by the IEEE,ANSI and military organizations.

These standards describe configuration management plans,documentation,specification practices,software comparisons,etc.Other standards which are currently under development include standards for reliability,measurement,the use of Ada as PDL[6],software testing and others.Bransta d and Powell(1984)describe both existing and planned software standards as well as discussing standardization in more general terms.

第 7 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

The problem with national software standards is that they tend to be very general in nature.

This is inevitable as,unlike hardware,we are not yet capable of quantifying most software characteristics.Effective quality assurance within an organization thus requires the development of more specific organizational standards.

Of course,the problem which arises in developing software standards for quality assurance and which makes the assessment of the level of excellence of a software product difficult to assess is the elusive nature of software quality.Boehm et al.(1978)suggest that quality criteria include but are not limited to:

Economy Correctness Resilience Integrity Reliability Usability Documentation Modifiability Clarity

Understandability Validity Maintainability Flexibility Generality Portability Interoperability Testability Efficiency Modularity Reusability

Exactly how some of these criteria may be quantified is not clear.Furthermore,as Buckley and Poston(1984)point out,parts of this definition may have no value for a particular product.It may be possible to transfer a system from a microcomputer to a large mainframe but this is often a nonsensical thing to do.Assessment of software quality thus still relies on the judgement of skilled individuals although this does not mean that it is necessarily inferior to quantitative assessment.After all,we cannot assess a painting or a play quantitatively yet this does not preclude a judgement of its quality. Within an organization,quality assurance should be carried out by an independent software quality assurance team who reports directly to management above the project manager level.The quality assurance team should not be associated with any particular development group but should be responsible for quality assurance across all project groups in an organization.

The activity of quality assurance involves sitting in on design reviews[7],program walkthroughs,etc. ,and reporting on the overall quality of the product as it is developed.It also involves checking that the finished product and its associated documentation conform to those standards which exist.The quality assurance team may also assess if the different representations of a product(requirements,design,code)are consistent and complete.

Notice that quality assurance is not the same as system testing.It is the development or testing team’s responsibility to validate the system,with the quality assurance team reporting on both the validation and the adequacy of the validation effort.This naturally involves quality assurance being closely associated with the final integration testing of the system.

Software quality assurance is now an emerging subdiscipline of software engineering[8].As Buckly and Poston point out,effective software quality assurance is likely to lead to an ultimate reduction in software costs.However,the major hurdle in the path of software management in this area is the lack of usable software standards.The development of accepted and generally applicable standards should be one of the principal goals of research in software engineering.

NOTES

[1] carried out... 分词短语修饰activities。

[2] with quality assurance... development介词with引导的独立分词结构,起补充说明的作用。 [3] 主句谓语是consists of,其宾语为分词短语修饰的procedures,techniques,and tools。 [4] of course:插入语,译为“当然”。

[5] 此句包括两个定语从句:第一个定语从句which defines中which指representation;第二个定语从句which the developed修饰performance,robustness,organization。

第 8 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

[6] Ada语言(一种程序设计语言,以Agusta Ada Byron命名);PDL:程序设计语言。

[7] sitting in on design reviews:列席设计评审会议。 [8] emerging subdiscipline of... :……的新兴分支。 KEYWORDS

software quality assurance 软件质量保证 software standard 软件标准

翻译:

软件质量保证活动与软件生存周期各阶段的验证和有效性确认活动紧密关联。事实上,在许多组织中这些活动没有明显的区别。尽管如此,质量保证实际上与其他验证和有效性确认活动相差甚远,质量保证是一个管理功能,而验证和有效性确认是软件开发过程的一部分。 Bersoff(1984)给出了软件质量保证的恰当定义:质量保证由在产品开发周期中专业人员要确保产品达到或超过某些预先设定的标准所要用到的那些过程、技术和工具所组成。如果没有具体的规定性的标准,质量保证则需要保证产品达到或超过工商业可接受的优良性能的最低标准。

当然这是一种相当笼统的定义。它首先指出软件标准可以建立;其次软件产品的优良程度可以评测。

软件工程项目标准的开发是一个非常困难的过程。一个标准是一个产品的某种抽象表示,它定义了被开发产品必须达到的最低性能、健壮性、结构等。在写此文章时,一些软件产品标准已经由IEEE,ANSI和一些军事机构制定了。

这些标准描述了配置管理计划、文档、规范实施、软件对照等。其他一些处于开发阶段的标准包括可靠性、测量方法、Ada用作为程序设计语言、软件测试和其他方面的标准。Bransta和Powell(1984)描述了已有的和已规划的软件标准,用更概括的语言讨论了标准化问题。

软件的国家标准问题在于这些标准过于笼统,这是必然的,因为不像硬件,我们至今尚不能将大多数软件特性进行量化。因此有效的质量保证就要求开发更多特定的组织标准。 当然,为质量保证而开发软件标准所带来的问题及软件产品的优良程度难于评估是软件质量难以把握的本质。Boehm等人(1978)提出的质量准则包括但不局限于: 经济性 正确性 弹性 完整性 可靠性 可使用性 文档 可修改性 明晰性 易理解性 合法性 可维护性 灵活性 通用性 可移植性 互操作性 可测试性 效率 模块性 可重用性

如何精确量化其中的某些准则尚不清楚。而且,正如Buckley 和 Poston(1984)指出的那样,此定义的某些部分对特定产品也许毫无价值。把一个系统从一台微机移到一台大型机上是可能的,但这样做往往是毫无用处的。因此,软件质量的评估仍然依赖于熟练的个人判断。尽管这并不意味着此方法一定比定量评估差。尽管我们不能定量地评价一幅画或一场演出,但这毕竟不能阻止对其质量的判断。 在一个组织内,质量保证应由一个独立的软件质量保证小组来实施,该小组直接向项目经理层之上的管理层报告。质量保证小组不应与任何开发小组有联系,但要对本组织中所有的项目组的质量保证负责。

质量保证活动包括旁听设计复审、程序走查等,并报告开发过程中产品的整体质量。质量保证也包括检查已完成产品及其有关的文件说明是否与现有标准一致。质量保证小组也可以评估一件产品的不同表示方式(需求、设计、代码)是否一致和完备。

注意,质量保证不同于系统测试。系统有效性确认是开发或测试小组的责任,而质量保证小组要报告确认和确认工作是否充分。这自然意味着质量保证与系统最后阶段的综合测试

第 9 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

有着密切的联系。

软件质量保证正成为软件工程的一个新兴分支。正如Buckley 和Poston所指出的,有效的软件质量保证很可能导致软件费用的最终降低。然而,在这一领域中软件管理的最主要障碍是缺乏适用的软件标准。为人们所接受和普遍适用的标准的开发应成为软件工程研究的一个主要目标。

软件需求模式之领域和基础架构

一些类型的需求依赖于基础架构,就像错误!未找到引用源。错误!未找到引用源。中“错误!未找到引用源。“中讨论的。需求模式使我们有机会确定一种类型的需求所依赖的基础架构,而不必为某一个需求考虑。而且我们可以进一步讨论每一个基础架构——也就是当为系统需要的基础架构定义需求时必须记住的。但是它不可能非常详细,也不可能针对实际的需求,因为每个组织,每个系统的不同要求,会使需求差别极大。为了清楚起见,它们被称作基础架构概述。

不能指望让每一个需求模式描述它需要的任何基础架构,这个解释的责任被给予了模式所属的领域。这是因为每个基础架构一般都会被领域中的多个模式使用。为了避免重复,每种基础架构只在一个领域中描述。本书中的每一章的模式中包含一节关于该领域的基础架构。本书讨论了三个基础架构:信息存储(错误!未找到引用源。错误!未找到引用源。),用户界面,以及报表(都在错误!未找到引用源。错误!未找到引用源。)。这几个关键概念的相互关系如图所示。

Domain: 领域

Infrastructure: 基础架构

Requirement Pattern: 需求模式 Depends Upon: 依赖

图 3-2领域,需求模式,以及基础架构之间的关系 需求模式可以自由使用其他领域中的基础架构。但是最好避免相互依赖,所以如果一个领域依赖另一个领域,那么后一个领域就不应该依赖前一个领域——如果可以避免的话。一个基础架构也可以依赖另一个基础架构。

基础架构概述应该说些什么呢?它的角色是指导和建议如何定义一个特定系统的基础架构的需求,提出需求需要覆盖的主题。最少,它应该陈述系统需要基础架构提供什么:它存在的目的是什么,它的主要功能。有些问题有很明显的替代解决方案,概述应该避免做判

第 10 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

断。

每个基础架构概述分成下列小节:

1. 目的解释基础架构存在的理由,以及扮演的角色。

2. 调用需求关于系统与基础架构如何交互的需求定义的建议——基础架构必须提供这些功能给系统——以及系统期望的其他的能力(比如访问控制)。需要的功能可以被看作是基础架构提供给调用者的接口。

3. 实现需求为了使基础架构站得住脚所需要的一些特性的想法(例如,查询,维护和配置功能)。这些是比较简短的,只是在定义基础架构时提醒一些需要考虑的可能的主要功能域。

例如,对于报表基础架构,调用需求可能是很简单:只是让系统请求运行一个选定的报表的功能。而另一方面,实现需求则相当多,包括交付报告给用户的各种方式的复杂性,其他请求报告的方式,设计报告,等等。(这些主题在错误!未找到引用源。错误!未找到引用源。进一步讨论。)以建造房屋类推,我们需要的基础架构之一是电力供应。这种情况下,调用需求是每个屋子需要多少插座,实现需求处理的是看不见的部分,像是与电网的连线,遵守建筑质量法。

软件项目开发实践中需要积累哪些知识

我们都知道在实践中学习积累的重要性,那么在应用软件的开发项目中,我们应该注意学习积累哪些知识呢?

常常看到一些程序员对某些软件开发技术和理论的执著,也常常听到一些程序员谈论某某项目的技术含量的话题。软件专业开发技术,作为程序员的立身之本,受到这样的厚爱是无可厚非的。但是软件作为一种多种知识集成的载体,我们不能只把眼光盯在专业的开发技术上,还应该看到其中包含的丰富软件应用领域的业务知识、开发过程中的控制管理知识,以及与客户同事之间的交流方式和手段,这些都应该成为我们在日常的开发过程积累的素材。

从项目实践中学习软件专业开发技术,是很容易被开发人员接受并在项目开发过程中加以关注和积累的,但是项目中的业务知识往往被大家所忽略,因为这些东西似乎与开发人员无关,其实大错特错了。考试,大提示就曾经历过这样的一个项目,项目中应用的开发技术大家都很熟悉,但是应用的业务领域都很陌生,在项目开始的初期对项目中的业务知识和术语进行了一些了解,但是由于业务流程和数据关系复杂,着实让我们吃了很多苦头不说,首次提交的成果物根本就满足不了客户的要求。现在回想起来还心有余悸。如果当时我们对业务都很熟悉的话,我们就可以更多的从客户应用的角度去思考问题,设计程序结构,解决客户问题了。少走很多弯路不说,开发过程也不回异常艰苦。 在开发实践中,我们在提高专业技能的同时,一定要注意软件中所包含的业务知识的积累,久而久之,我们很自然的就会把软件专业知识和行业业务知识结合到一起,在项目开发过程中不但能够游刃有余,而且还可以减少跟客户的沟通障碍,想客户之所想,为客户提供更好的软件解决多方案。

软件系统与软件系统之间的集成交互问题

可能写得有些乱,希望能谅解,同时我整理的思想,希望能给您带来一些启发或者帮助。 我们假设一个国际化的大公司里,有来自多个国家的员工,这些员工又工作在不同的部

第 11 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

门里,负责不同的任务。

首先:

1. 这些人可能是白人,也可能是黑人,也可能是黄皮肤的我们,这就像我们软件开发里的语言一样,有的是.NET体系,有的是JAVA体系的。所以不太可能要求一个公司里的人必须全部是黄皮肤的,或者是某个民族的,那就是歧视种族的问题了,通过这个例子我想说一下,没必要非是.NET或者是JAVA必须是你死我活,我以前在这个问题上犯过严重错误,现在终于想通了。

【.NET、JAVA并不是非要你死我活】

2. 对于一个规范的公司来讲,每个人的分工是很明确的,例如财务就是干啥的,人力资源有是干啥的,他们分工很明确,不可能是一个人啥事情都干了,很容易干不好,或者干不专业。对我们开发人员来讲,就是意味着我们的某个系统,应该有个明确的功能定位,应该有个明确的分工,不太可能某个系统是万能的,也就不存在多个系统之间的集成问题所在了。

【分工就乱,集成就更乱了,甚至是不可能集成了】

3. 规范的公司,都应该有些制度,不应该是财务管招聘,人事是管财务报表,应该是哪个部门做什么事情,对什么事情负责,那个部门是哪些数据的权威来源,例如,我们登录系统的帐号,应该是人事部门管理,我们的公司的财务报表应该是从财务部门获取,不应该是每个部门都有独立全套的数据,应该是负责他该负责的部分,说白了,还是跟上面的2有些类似,分工明确,责任明确。

【重复的数据,以哪个来源为标准依据】

4.部门与部门的沟通,员工与员工的沟通的,我们国家政府部门之间沟通,都用标准的公文形式,这也是个沟通方式,沟通可以是书面的,也可以口头的,这个类似于我们到底用 WebServeric、Remoting、WCF等一样,沟通还可以用英文、中文或日文,只要这两个互相沟通的员工能说清楚就可以了,互相能读懂就可以了,事情能办理好了。

【标准接口,有输入输出,例如公文能发出去另一方还需要能接收公文】

其次:

对现实中的软件系统之间的交互集成的理解,先不谈Biztalk、EAI等,那不是我的思想,那需要花费巨资才能购买。

1. 我们经常能实现的系统之间的交互,通过分析底层的数据库结构,然后适当的进行添加触发器等机制,可以完成系统之间的数据交互,这个虽然不是好方法,但是也是迫不得已的方法,不用修改程序代码。

2. 我们可以直接利用应用系统的页面,将数据进行导入导出操作,直接导入到另外一个系统,最理想的状态是,这2个系统最起码都有导入导出功能,这样避免了同样的数据在2个系统中重复录入的罪孽。

所以,现在开发的系统,都应该有批量导入导出功能,否则,不算是一个开放的系统。但是这个有个不好的地方是,也是严重的缺陷是,都是要人工进行干预,需要在两个系统之间奔波,也是很辛苦的事情。

3. 最理想的状态是,在应用程序之间能互相调用,用户只在一个系统里录入,另一个系统将在被后台自动调用。这时就是需要2个系统都有规范的接口定义,可调用的公开方法及手段。现在大部分公司都忽视这部分的要求,以后应该是越来越重视这部分的工作。应该成为软件验收的重要功能指标之一了,现在很多公司里,同样的数据需要重复录入的问题很

第 12 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

严重,甚至是电子化没有解放我们,而是越电子化,我们越变成了电脑软件的奴隶,需要将

同样的数据,在不同的软件里录入,悲哀啊,最可怜的是那那些最底层的员工,让他们录入数据,他们必须得录入,虽然很反感,没办法啊,领导的命令下来了。

大家开发的系统都应该有可编程接口,可进行数据录入、调用核心业务处理流程,这样我们的政府、企业信息化会更顺利,大家也不会排斥上多个IT系统了,现在推IT系统也很难,人家就怕重复录入数据,不是怕花钱。 最近在杭州临安做项目,看到银行的电子转账程序,可以将需要转账的数据,类似Excel一样,批量的复制粘贴,若是一个个人必须通过页面输入,那这个软件真的难用得要命了,人家有一个功能,可以批量导入或者批量复制粘贴,可以从另一个系统导入数据或者从另一个系统批量复制数据,然后直接粘贴到这个类似Excel的页面里就可以,用户不会觉得很繁琐,复制粘贴一下就可以,甚至不用导入导出了,感觉很好用的,我们开发的系统也应该多多借鉴。

将权限管理、工作流管理做到我能力的极致,一个人只能做好那么很少的几件事情。

软件体系结构与软件架构解析

软件体系结构与软件架构的中文翻译都是英文Software Architecture。两者都使用一样的定义,如IEEE的“一个系统的基础组织,包含各个构件、构件互相之间与环境的关系,还有指导其设计和演化的原则。”*IEEE-2000]

为了找到两者的区别,得先从应用的环境入手。

① http://www-128.ibm.com/developerworks/cn

② http://www.miscrosoft.com/china

③ google.com 采用精确匹配。“架构师”改为“软件架构师”,“架构设计师”改为“软件架构设计师”减少领域差异

④ http://www.wodefanwen.com/ 采用精确匹配。“架构师”改为“软件架构师”,“架构设计师”改为“软件架构设计师”减少领域差异

⑤ http://www.cnki.net/index.htm采用精确匹配。中国期刊全文数据库(2000-2007)

结果表明,在软件开发者和软件应用者来说,倾向于使用“软件架构”,在一定程度上接受“软件体系结构”。大家对软件架构的设计人员,“架构师”得到广泛的认同。对于学术界,普遍使用“软件体系结构”,对架构师几乎没有关注。Software Architecture是一个实践性非常强的领域,统计表明理论和实践的鸿沟还是存在的。

其次,我们从词源探讨“体系”“结构”“架构”的解释[字典-2001]。 体系:若干事物互相联系而构成的一个整体。例思想~ | 工业~

结构:①建筑物承受重量和外力的部分及其制造。按材料分有钢结构、木结构、砖石结构、框架结构、砖混结构等。按形式分有悬索结构、拱结构等。②构成整体的各个部分及其结合方式。例经济~│文章~。③文艺作品的内部构造。即作品的各部分(包括内容和形式)之间有机的组织联系。

架构:①建造;构筑。②框架;支架。③比喻事物的组织、结构、格局。例市场~│故事~庞大

通过以上分析,我们不难看出学术界为什么用“软件体系结构”。首先,体系结构的中文定义完全符合IEEE等的定义。强调整体与部分,部分与部分的关系;研究系统构成的方法学;提倡多角度研究系统。其次,从学科地位讲,作为一门独立软件子学科,和硬件学科(计

第 13 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

算机组织与体系结构)直接对应。

从工程实践需要看,软件架构更能体现系统构成与相关技术。RUP过程或软件生产线关注的软件架构并不注重原理及表示,而是由结构和技术相结合的形成框架。

软件架构在中文中很容易与软件框架(Software Framework)混淆,对于一个应用的软件框架通常称为应用程序框架(Application Framework)。框架是为了构建完整的应用而必须详细阐述的一种程序结构[Johnson-88]。框架在RUP和软件产品线开发过程中是一个非常重要的过程。RUP中框架是细化阶段的一个制品,软件产品生产线中是一组应用共享的程序框架。

目前,没有文献表明软件体系结构与软件架构的差别。如果你强调方法论,应使用软件体系结构。强调软件开发实践,应使用软件架构。

[IEEE-2000] IEEE 1471-2000, IEEE Recommended Practice for Architectural Descriptions of Software Intensive Systems

[字典-2001] 新华词典,2001年修订版. 商务印书社 2005 北京

[Johnson-88] Ralph E.Johnson & Brian Foote. Designing reusable classes. Journal of Object-Oriented Programming 1,3(June/July 1988),22-35

软件体系结构的描述方法

从软件体系结构研究和应用的现状来看,当前对软件体系结构的描述,在很大程度上来说还停留在非形式化的基础上,很大程度上依赖于软件设计师个人的经验和技巧。在目前通用的软件开发方法中,其对软件体系结构的描述通常是采用非形式化的图和文本,不能描述系统期望的存在于构件之间的接口,更不能描述不同的组成系统的组合关系的意义。这种描述方法难以被开发人员理解,难以适于进行形式化分析和模拟,缺乏相应的支持工具帮助设计师完成设计工作,更不能用来分析其一致性和完整性等特性。

因此,形式化的、规范化的体系结构描述对于体系结构的设计和理解都是非常重要的。然而,要实现体系结构设计、描述等的形式化并不是一蹴而就的,我们必须先经历一个非形式化的过程,在非形式化的发展过程中逐步提取一些形式化的标记和符号,然后将它们标准化,从而完成体系结构设计、描述等的形式化。

本文首先简单地介绍传统的软件体系结构描述方法,然后再比较详细地讨论软件体系结构描述语言。

一、传统软件体系结构描述方法 1、图形表达工具

对于软件体系结构的描述和表达,一种简洁易懂且使用广泛的方法是采用由矩形框和有向线段组合而成的图形表达工具。在这种方法中,矩形框代表抽象构件,框内标注的文字为抽象构件的名称,有向线段代表辅助各构件进行通讯、控制或关联的连接件。例如:图1表示某软件辅助理解和测试工具的部分体系结构描述。 目前,这种图形表达工具在软件设计中占据着主导地位。尽管由于在术语和表达语义上存在着一些不规范和不精确,而使得以矩形框与线段为基础的传统图形表达方法在不同系统和不同文档之间有着许多不一致甚至矛盾,但该方法仍然以其简洁易用的特点在实际的设计和开发工作中被广泛使用,并为工作人员传递了大量重要的体系结构思想。

为了克服传统图形表达方法中所缺乏的语义特征,有关研究人员试图通过增加含有语义的图元素的方式来开发图文法理论。

2、模块内连接语言

软件体系结构的第二种描述和表达方法是采用将一种或几种传统程序设计语言的模块连接起来的模块内连接语言MIL(Module Interconnection Language)。由于程序设计语言和

第 14 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

模块内连接语言具有严格的语义基础,因此他们能支持对较大的软件单元进行描述,诸如定

义/使用和扇入/扇出等操作。

MIL方式对模块化的程序设计和分段编译等程序设计与开发技术确实发挥了很大的作用。但是由于这些语言处理和描述的软件设计开发层次过于依赖程序设计语言,因此限制了他们处理和描述比程序设计语言元素更为抽象的高层次软件体系结构元素的能力。

3、基于软构件的系统描述语言

软件体系结构的第三种描述和表达方法是采用基于软构件的系统描述语言。基于软构件的系统描述语言将软件系统描述成一种是由许多以特定形式相互作用的特殊软件实体构造组成的组织或系统。

这种表达和描述方式虽然也是较好的一种以构件为单位的软件系统描述方法,但是他们所面向和针对的系统元素仍然是一些层次较低的以程序设计为基础的通信协作软件实体单元,而且这些语言所描述和表达的系统一般而言都是面向特定应用的特殊系统,这些特性使得基于软构件的系统描述仍然不是十分适合软件体系结构的描述和表达。

二、体系结构描述语言

软件体系结构的第四种描述和表达方法是参照传统程序设计语言的设计和开发经验,重新设计、开发和使用针对软件体系结构特点的专门的软件体系结构描述语言ADL(Architecture Description Language),由于ADL是在吸收了传统程序设计中的语义严格精确的特点基础上,针对软件体系结构的整体性和抽象性特点,定义和确定适合于软件体系结构表达与描述的有关抽象元素,因此,ADL是当前软件开发和设计方法学中一种发展很快的软件体系结构描述方法。

ADL是这样一种形式化语言,它在底层语义模型的支持下,为软件系统的概念体系结构建模提供了具体语法和概念框架。基于底层语义的工具为体系结构的表示、分析、进化、细化、设计过程等提供支持。其三个基本元素是: ※ 构件:计算或数据存储单元;

※ 连接件:用于构件之间交互建模的体系结构构造块及其支配这些交互的规则; ※ 体系结构配置:描述体系结构的构件与连接件的连接图。

主要的体系结构描述语言有Aesop、MetaH、C2、Rapide、SADL、Unicon和Wright等,尽管它们都描述软件体系结构,却有不同的特点。Aesop支持体系结构风格的应用,MetaH为设计者提供了关于实时电子控制软件系统的设计指导,C2支持基于消息传递风格的用户界面系统的描述,Rapide支持体系结构设计的模拟并提供了分析模拟结果的工具,SADL提供了关于体系结构加细的形式化基础,Unicon支持异构的构件和连接类型并提供了关于体系结构的高层编译器,Wright支持体系结构构件之间交互的说明和分析。这些ADL强调了体系结构不同的侧面,对体系结构的研究和应用起到了重要的作用,但也有负面的影响。每一种ADL都以独立的形式存在,描述语法不同且互不兼容,同时又有许多共同的特征,这使设计人员很难选择一种合适的ADL,若设计特定领域的软件体系结构又需要从头开始描述。

1、ADL与其他语言的比较

按照Mary Shaw和David Garlan的观点,典型的ADL在充分继承和吸收传统程序设计语言的精确性和严格性特点的同时,还应该具有构造、抽象、重用、组合、异构和分析推理等各种能力和特性。其中:

◇ 构造能力指的是ADL能够使用较小的独立体系结构元素来建造大型软件系统; ◇ 抽象能力指的是ADL使得软件体系结构中的构件和连接件描述可以只关注它们的抽象特性,而不管其具体的实现细节;

◇ 重用能力指的是ADL使得组成软件系统的构件、连接件甚至是软件体系结构都成为软件系统开发和设计的可重用部件;

第 15 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

◇ 组合能力指的是ADL使得其描述的每一系统元素都有其自己的局部结构,这种描述

局部结构的特点使得ADL支持软件系统的动态变化组合;

◇ 异构能力指的是ADL允许多个不同的体系结构描述关联存在;

◇ 分析和推理能力指的是ADL允许对其描述的体系结构进行多种不同的性能和功能上的多种推理分析。

根据这些特点,我们可以将下面这样的语言排除在ADL之外:高层设计符号语言、MIL、编程语言、面向对象的建模符号、形式化说明语言。ADL与需求语言的区别在于后者描述的是问题空间,而前者则扎根于解空间中。ADL与建模语言的区别在于后者对整体行为的关注要大于对部分的关注,而ADL集中在构件的表示上。ADL与传统的程序设计语言的构成元素即有许多相同和相似之处,又各自有着很大的不同。

2、ADL的构成要素

前面,我们提到了体系结构描述的基本构成要素有构件、连接件和体系结构配置,软件体系结构的核心模型。 (1)构件

构件是一个计算单元或数据存储。也就是说,构件是计算与状态存在的场所。在体系结构中,一个构件可能小到只有一个过程或大到整个应用程序。它可以要求自己的数据与/或执行空间,也可以与其它构件共享这些空间。作为软件体系结构构造块的构件,其自身也包含了多种属性,如接口、类型、语义、约束、进化和非功能属性等。

接口是构件与外部世界的一组交互点。与面向对象方法中的类说明相同,ADL中的构件接口说明了构件提供的那些服务(消息、操作、变量)。为了能够充分地推断构件及包含它的体系结构,ADL提供了能够说明构件需要的工具。这样,接口就定义了构件能够提出的计算委托及其用途上的约束。 构件作为一个封装的实体,只能通过其接口与外部环境交互,构件的接口由一组端口组成,每个端口表示了构件和外部环境的交互点。通过不同的端口类型,一个构件可以提供多重接口。一个端口可以非常简单,如过程调用。也可以表示更为复杂的界面,如必须以某种顺序调用的一组过程调用。

构件类型是实现构件重用的手段。构件类型保证了构件能够在体系结构描述中多次实例化,并且每个实例可以对应于构件的不同实现。抽象构件类型也可以参数化,进一步促进重用。现有的ADL都将构件类型与实例区分开来。

由于基于体系结构开发的系统大都是大型、长时间运行的系统,因而系统的进化能力显得格外重要。构件的进化能力是系统进化的基础。ADL是通过构件的子类型及其特性的细化来支持进化过程的。目前,只有少数几种ADL部分地支持进化,对进化的支持程度通常依赖于所选择的程序设计语言。其他ADL将构件模型看作是静态的。ADL语言大多是利用语言的子类型来实现对进化支持的。利用面向对象方法,从其它类型派生出它的接口类型,形成结构子类型。

(2)连接件

连接件是用来建立构件间的交互以及支配这些交互规则的体系结构构造模块。与构件不同,连接件可以不与实现系统中的编译单元对应。它们可能以兼容消息路由设备实现(如C2),也可以以共享变量、表入口、缓冲区、对连接器的指令、动态数据结构、内嵌在代码中的过程调用序列、初始化参数、客户服务协议、管道、数据库、应用程序之间的SQL语句等形式出现。大多数ADL将连接件作为第一类实体,也有的ADL则不将连接件作为第一类实体的。

连接件作为建模软件体系结构的主要实体,同样也有接口。连接件的接口由一组角色组成,连接件的每一个角色定义了该连接件表示的交互参与者,二元连接有两个角色,如消息传递连接件的角色是发送者和接收者。有的连接件有多于两个的角色,如事件广播有一个事件发布者角色和任意多个事件接受者角色。

第 16 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

显然,连接件的接口是一组它与所连接构件之间的交互点。为了保证体系结构中的构件

连接以及它们之间的通信正确,连接件应该导出所期待的服务作为它的接口。它能够推导出正交软件体系结构线索的形成情况。体系结构配置中要求构件端口与连接件角色的显式连接。

体系结构级的通讯需要用复杂协议来表达。为了抽象这些协议并使之能够重用,ADL应该将连接件构造为类型。构造连接件烈性可以将作为用通信协议定义的类型系统化并独立于实现,或者作为内嵌的、基于它们的实现机制的枚举类型。

为完成对构件接口的有用分析、保证跨体系结构抽象层的细化一致性,强调互联与通信约束等,体系结构描述提供了连接件协议以及变换语法。为了确保执行计划的交互协议,建立起内部连接件依赖关系,强制用途边界,就必须说明连接件约束。ADL可以通过强制风格不变性来实现约束,或通过接受属性限制给定角色中服务。

(3)体系结构配置

体系结构配置或拓扑是描述体系结构的构件与连接件的连接图。体系结构配置提供信息来确定构件是否正确连接、接口是否匹配、连接件构成的通信是否正确,并说明实现要求行为的组合语义。

体系结构适合于描述大的、生命周期长的系统。利用配置来支持系统的变化,使不同技术人员都能理解并熟悉系统。为帮助在一个较高的抽象层上理解系统,就需要对软件体系结构进行说明。为了使开发者与其有关人员之间的交流容易些,ADL必须以简单的、可理解的语法来配置结构化信息。理想的情况是从配置说明中澄清系统结构,即不需研究组件与连接件就能使构建系统的各种参与者理解系统。体系结构配置说明除文本形式外,有些ADL还提供了图形说明形式。文本描述与图形描述可以互换。多视图、多场景的体系结构说明方法在最新的研究中得到了明显的加强。

为了在不同细节层次上描述软件系统,ADL将整个体系结构作为另以个较大系统的单个构件。也就是说,体系结构具有复合或等级复合的特性。另一方面,体系结构配置支持采用异构构件与连接件。这是因为软件体系结构的目的之一是促进大规模系统的开发,即倾向于使自己有的构件与不同粒度的连接件,这些构件与连接件的设计者、形式模型、开发者、编程语言、操作系统、通信协议可能都不相同。另外一个事实是,大型的、长期运行的系统是在不断增长的。因而,ADL必须支持可能增长的系统的说明与开发。大多数ADL提供了复合特性,所以,任意尺度的配置都可以相对简洁地在足够的抽象高度表示出来。

三、结束语

我们知道,体系结构设计是整个软件生命周期中关键的一环,一般在需求分析之后,软件设计之前进行。而形式化的、规范化的体系结构描述对于体系结构的设计和理解都是非常重要的。因此,ADL如何能够承上启下将是十分重要的问题,一方面是体系结构描述如何向其它文档转移,另一方面是如何利用需求分析成果来直接生成系统的体系结构说明。

现有的ADL大多是与领域相关的,这不利于对不同领域体系结构的说明。这些针对不同领域的ADL在某些方面又大同小异,造成了资源的冗余。有些ADL可以实现构件与连接件的进化,但这样的进化能力是有限的,这样的进化大多是通过子类型实现的。而且,系统级的进化能力才是最终目的。尽管现有的ADL都提供了支持工具集,但将这些ADL与工具应用于实际系统开发中的成功范例还有限。支持工具的可用性与有效性较差,严重地阻碍了这些ADL的广泛应用。

软件设计阅读(中英文对照)习题及答案

EXERCISES

1.Multiple choices.

第 17 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

(1)Software design may .

a.be a creative process b.not be learned from a book c.be learned from a book

d.require a certain amount of flair

(2)Methodologies of software design can be classified into . a.down-top function design b.data-driven design

c.top-down function design d.object-oriented design

(3)A well-designed system should be . a.easily understood b.reliable

c.straightforward to implement d.straightforward to maintain

(4)A derivation process for designing a programming system includes stages. a.5 b.4 c.3 d.2

(5)In the early stage of software design we need . a.give a flowchart

b.give a set of requirements

c.top-down functional design only d.prepare an informal design

(6)A good design of software depends on . a.establishing a definitive way b.the application

c.the particular project requirements d.efficient code to be produced

(7)Software design can be . a.represented in any single notation b.a multi-stage activity c.an iterative activity d.a single-stage activity

(8)The tasks being performed by a software engineer are . a.to design communication mechanisms b.to design file structures c.to design data structures

d.to derive the design of a programming system

2.Fill in the blanks with appropriate words or phrases.

(1)To accomplish a effective software design we should use .

第 18 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

(2)Good software design is the key to .

(3)If the software design is highly cohesive and loosely coupled,we can achieve . (4)A programming system may have multiple .

(5)Structured design and stepwise refinement are the examples of . (6)An essential part of the software design process is . (7)A maintainable design implies that .

(8)Object-oriented design can be viewed as .

(9)In a programming system each subsystem must be decomposed into .

(10)Design that is derived from an analysis of the input and output system data is a . a.separate components

b.top-down functional design

c.a consistent design methodology d.data-driven design

e.very efficient code and minimal design f.the cost of system changes is minimized g.a collection of objects

h.effective software engineering i.subsystems

j.the precise specification

答案: 1.

(1)a,b,d (2)b,c,d (3)a,b,c,d (4)a

(5)a,b,d (6)a,c,d (7)b,c

(8)a,b,c,d 2.

(1)c (2)h (3)e (4)i (5)b (6)j (7)f (8)g (9)a (10)d

软件设计阅读(中英文对照)

SOFTWARE DESIGN

Software design is a creative process.It requires a certain amount of flair on the part of the

第 19 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

designer and the final design is normally an iteration from a number of preliminary

designs.Design cannot be learned from a book—it must be practiced and learnt by experience and study of existing systems.Good design is the key to effective software engineering.A well-designed software system is straightforward [1] to implement and maintain,easily understood and reliable.Badly designed systems,although they may work,are likely to be expensive to maintain,difficult to test and unreliable.The design stage is therefore the most critical part of the software development process.

Until fairly recently,software design was largely an ad hoc[2] process.Given a set of requirements,usually in natural language,an informal design was prepared,often in the form of a flowchart[3].Coding then commenced and the design was modified as the system was implemented.When the implementation stage was complete,the design had usually changed so much from its initial specification that the original design document was a totally inadequate description of the system.

This approach to software design was responsible for many dramatic and very expensive project failures.Now it is realized that completely informal notations such as flowcharts,which are close to the programming language,are inadequate vehicles for formulating and expressing system design.It is recognized that precise(although not necessarily formal)specification is an essential part of the design process and that software design is an iterative,multi-stage activity which cannot be represented in any single notation.Accordingly,a number of design notations such as data flow diagrams.HIPO charts[4],structure diagrams and design description languages have been developed which are superior to flowcharts for expressing software designs. Given a requirements definition,the software engineer must use this to derive the design of a programming system which satisfies these requirements.This derivation is accomplished in a number of stages:

(1)The subsystems making up the programming system must be established.

(2)Each subsystem must be decomposed into separate components and the subsystem specification established by defining the operation of these components.

(3)Each program may then be designed in terms of interacting subcomponents.

(4)Each component must then be refined.This normally entails specifying each component as hierarchy of subcomponents.

(5)At some stage of this refinement process,the algorithms used in each component must be specified in detail.

As well as these various stages of programming system design,the software engineer may also be required to design communication mechanisms allowing processes in the system to communicate[5].He or she may have to design file structures,and will almost certainly have to design the data structures used in his programs.He or she will have to design test cases to validate his programs.

There is no definitive way of establishing what is meant by a“good”design.Depending on the application and the particular project requirements,a good design might be a design which allows very efficient code to be produced,it might be a minimal design where the implementation is as compact as possible,or it might be the most maintainable design.This latter criterion is the criterion of“goodness”adopted here.A maintainable design implies that the cost of system changes is minimized and this means that the design should be understandable and that changes should be local in effect.Both of these are achieved if the software design is

第 20 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

highly cohesive and loosely coupled[6].

Effective software design is best accomplished by using a consistent design methodology.There have been a vast number of design methodologies developed and used in different applications.Some of these are described by Peters(1980)and by Blank and Krijger(1983).In essence,most of these methodologies can be classified into one of three areas: (1)Top-down functional design.The system is designed from a functional viewpoint,starting with a high-level view and progressively refining this into a more detailed design.This methodology is exemplified by Structured Design and stepwise refinement.

(2)Object-oriented design.The system is viewed as a collection of objects rather than as functions with messages passed from object to object.Each object has its own set of associated operations.Object-oriented design is based on the idea of information hiding which was first put forward by Parnas(1972)and which has been described more recently by Robson(1981)and Booch(1983).

(3)Data-driven design.This methodology,suggested by Jackson(1975)and Warnier(1977)suggests that the structure of a software system should reflect the structure of the data processed by that system.Therefore,the software design is derived from an analysis of the input and output system data.

NOTES

[1] straightforward:直接了当的,简单明了的。 [2] ad hoc:特别的(地)。 [3] flowchart:流程图。

[4] HIPO charts:层次输入一处理一输出图。

[5] allowing... :修饰communication mechanisms。 [6] loosely coupled:松散地耦合。 KEYWORDS

software design 软件设计

object-oriented design 面向目标的设计 maintainable design 可维护性设计 data-driven design 数据驱动的设计

top-down functional design 自顶向下的功能设计

软件设计是一个创造性的过程,对一些设计者来说需要一定的资质,而最后设计通常都是由若于初步设计反复比较而来。从书本上学不会设计,只能经过实践.通过对一现有系统的研究和实际演练才能做到。对于能产生预期结果的软件工程,良好的设计是关键。设计得好的软件系统实现和维护方式简单明了、易懂可靠。设计得不好的系统,尽管可以工作,但很可能维护费高、测试困难且不可靠。因此,设计阶段是软件开发过程中最重要的阶段。 直到最近,软件设计在很大程度上仍是一个特定过程。一般用自然语言,给定一系列需求,准备好非正式设计,并常常用流程图的形式说明;接着开始编码;当系统实现时设计还会修改。当实现阶段完成后,设计往往与当初的规格说明相去甚远,以至于原始文档完全不适合对系统的描述。

软件设计的这种方法导致了许多惊人的而且是代价很大的工程失败。现在已经认识到一些完全非正式的表示法,诸如接近于编程语言的流程图,不适用于系统设计的公式化和表达。大家认识到,精确(尽管并不一定是正式)的规格说明是设计过程的必要部分。软件设计是一个反复的、不能用任何单一表示法来表示的多阶段活动。相应地,大量的设计表示法,如数据流图、层次化输入一处理一输出结构图和设计描述语言已经开发出来,比流程图能更好地表达软件设计。

第 21 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

对于给定的需求定义,软件工程师必须据此导出满足这些需求的程序系统的设计。此导

出过程是通过下述步骤来完成的:

(1)必须建立组成程序系统的子系统;

(2)必须把每个子系统分解成独立的成分,并且通过定义这些成分的操作来建立子系统规格说明;

(3)每个程序可以用相互作用的子成分设计;

(4)每个成分还须进行优化,这通常需要将每个成分规定为层次式的子成分;

(5)在精化过程中的某个阶段,各成分中的算法必须详细规定。 除了程序系统设计中的这些阶段之外,软件工程师也可能需要设计允许系统中各进程之间进行通信的通信机制。他们或许要设计文件结构,并且几乎必然要设计用于程序的数据结构,他们还需要设计确认程序的测试用例。

确定何为“成功”的设计无一定之规。依据应用和特定的工程要求。一个成功的设计应该是:能生成高效的代码,实现尽量紧凑的最小设计或最易维护的设计。最后一个准则是本文采用的优良度准则。可维护性设计意指系统修改费用最低,设计易于理解和修改是局部性的。只有高度内聚而又松散藕合的软件设计才能实现以上两个目标。 有效的软件设计最好利用一致性设计方法学。有大量的在不同应用环境中开发并使用的设计方法学。其中有些是由Yeters(1980),Blank 和 Krijger(1983)阐述的。实质上,这些方法学大多数和划分为3类。

(1)自顶向下的功能设计:从功能的观点设计系统,从高层的观点着手逐步提炼成更具体的设计。结构化设计和逐步求精就是使用此方法的例子。

(2)面向对象的设计:把系统作为对象集合而不是功能的集合,消息在对象与对象之间传送,每个对象都有自己的关联操作集。面向对象的设计方法是基于信息隐藏的思想,该思想由Parnas(1972)最先提出,最近又由Robson(1981)和Booch(1983)加以描述。

(3)数据驱动的设计:此方法由Jackson(1975)和Warnier(1977)提出,认为软件系统的结构应该反映该系统所处理的数据的结构。因此,软件设计应从对系统输入、输出数据进行分析中导出。

软件设计师知识点:面向对象语言概论(一)

面向对象语言概论

(译自Martin Abadi, Luca Cardelli的对象理论一书的第一部分) 译者前言

这本书是我们上面向对象类型理论的教材。当时上这门课时,心里满不以为然,觉得自己的C++和OO已经颇有造纸,C++和Java的类型系统不说倒背如流,也是轻车熟路,上这么一门课不是白拿学分?哈哈!

但一上起来,才发现自己竟如井底之蛙一样。老天,原来就这么简单的面向对象竟有这么多说道!原来除了C++, Java, 面向对象还有这么多没见过甚至没想过的东西!

前几章概论,勉强还都搞定了。但后面上到类型系统的建模,subject reduction的证明,就发现自己就象回到了本科时代,这,这,这怎么都是数学啊!

这两天心血来潮。就想把它翻译一下。后面艰深的地方自觉功力太浅,就不不自量力了。不过,倒可以把前面几章的概论翻译一下,如果能起到帮助大家开阔眼界的作用,也就没白费

第 22 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

劲。

第二章,基于类的面向对象语言

基于类的面向对象语言是面向对象世界里的主流。它包括: Simula, 第一个面向对象语言

Smalltalk, 第一个支持动态类型的语言

C++, 它的大部分基于类的特性继承自Simula. 等等等等。

与基于类的语言相对应的是基于对象的面向对象语言。这里“基于对象”的概念和把Visual Basic叫做基于对象的概念是不同的。这里的“基于对象”是指一个只以对象为中心,没有类的概念的语言,类似Python之类的语言。

现在,我们来介绍一下基于类的面向对象语言的一些共同特征。

1.类和对象

让我们先看一个类的定义: class cell is

var contents: Integer :=0; method get(): Integer is return self.contents; end;

method set(n:Integer) is self.contents := n; end; end;

一个类是用来描述所有属于这个类的对象的共同结构的。这个cell类表示的对象拥有一个叫做contents的整数属性(attribute),这个属性被初始化成0。它还描述了两个操作contents的方法。Get和set. 这两个方法的内容都是很直观的。Self变量表示这个对象自己。 对象的动态语义可以这样理解:

一个对象在内部被表示为一个指向一组属性的指针。任何对这个对象的操作都会经过这个指针操作对象的属性和方法。而当对象被赋值或被当作参数传递的时候,所传递的只是指针,这样一来,同一组属性就可以被共享。

(注, 有些语言如C++, 明确区分指向属性组的指针和属性组本身,而一些其它的语言则隐藏了这种区别)

对象可以用new从一个类中实例化。准确地说,new C分配了一组属性,

并返回指向这组属性的指针。这组属性被赋予了初始值,并包括了类C所定义的方法的代码。

下面我们来考虑类型。对一个new C所生成的对象,我们把它的类型记为InstanceTypeOf(c). 一个例子是:

var myCell: InstanceTypeOf(cell) := new cell;

这里,通过引入InstanceTypeOf(cell), 我们开始把class和type区分开来了。我们也可以把cell本身当作是类型,但接下来,你就会发现,那样做会导致混淆的。

2.方法解析。(Method Lookup)

给出一个方法的调用o.m(……), 一个由各个语言自己实现的叫做方法解析的过程负责找到正确的方法的代码。(译者按:是不是想起了vtable了?)。

直观地看,方法的代码可以被嵌入各个单个对象中,而且,对于许多面向对象语言,对属性和方法的相似的语法,也确实给人这种印象。 不过,考虑到节省空间,很少有语言这样实现。比较普遍的方法是,语言会生成许多method

第 23 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

suite, 而这些method suite可以被同一个类的对象们所共享。方法解析过程会延着对象内指

向method suite的指针找到方法。

在考虑到继承的情况,方法解析会更加复杂化。Method suite也许会被组成一个树,而对一个方法的解析也许要查找一系列method suite. 而如果有多继承的话,method suite甚至可能组成有向图,或者是环。

方法解析可能发生在编译时,也可能发生在运行时。

在一些语言中,方法到底是嵌入对象中的,还是存在于method suite中这种细节,对程序员是无关紧要的。因为,所有能区分这两种模式的语言特性一般在基于类的面向对象语言中都不被支持。 比如说,方法并不能象属性一样从对象中取出来当作函数使用。方法也不能象属性一样在对象中被更新。(也就是说,你更新了一个对象的方法,而同一个类的其它对象的该方法保持不变。)

3. 子类和继承 (Subclassing and Inheritance)

子类和一般的类一样,也是用来描述对象的结构的。但是,它是通过继承其它类的结构来渐进式地实现这个目的。

父类的属性会被隐式地复制到子类,子类也可以添加新的属性。在一些语言中,子类甚至可以override父类的属性(通过更改属性的类型来实现) 父类中的方法可以被复制到子类,也可以被子类override. 一个子类的代码的示例如下: subclass reCell of cell is

var backup: Integer := 0; override set(n: Integer) is

self.backup := self.contents; super.set(n); end;

method restore() is

self.contents := self.backup; end; end;

对有subclass的方法解析,根据语言是静态类型还是动态类型而有所不同。

在静态类型的语言(如C++, Java)里,父类,子类的method suite的拓扑结构在编译时就已经确定,所以可以把父类的method suite里的方法合并到子类的method suite中去,方法解析时就不用再搜索这个method suite的树或图了。(译者按:C++的vtable就是这种方法) 而对于动态类型的语言,(也就是说,父子类的关系是在运行时决定的),method suite就无法合并了。所以,方法解析时,就要沿着这个动态生成的树或有向图搜索直到找到合适的方法。而如果语言支持多继承,这个搜索就更复杂了。

软件设计师知识点:面向对象语言概论(二)

4. Subsumption和Dynamic Dispatch (译者按:呵呵,黔驴技穷,找不到合适的翻译了)

从上述的几个例子来看,似乎子类只是用来从父类借用一些定义,以避免重复。但是,当我们考虑到subsumption, 事情就有些不同了。什么是Subsumption呢?请看下面这个例子: var myCell: InstanceTypeOf(cell) := new cell;

var myReCell: InstanceTypeOf(reCell) := new reCell; procedure f(x: InstanceTypeOf(cell)) is … end; 再看下面这段代码: myCell := myReCell;

第 24 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

f(myReCell);

在这两行代码中,头一行把一个InstanceTypeOf(reCell)类型的变量赋值给一个InstanceTypeOf(cell)的变量。而第二行则用InstanceTypeOf(reCell)类型的变量作为参数传递给一个参数类型为InstanceTypeOf(cell)的函数。

这种用法在类似Pascal的语言中是不合法的。而在面向对象的语言中,依据以下的规则,它则是完全正确的用法。该规则通常被叫做subtype polimorphism, 即子类型多态(译者按:其实subtyping应该是OO语言最区别于其它语言的地方了)

如果c’是c的子类,并且o’是c’的一个实例,那么o’也是c的一个实例。 更严格地说:

如果c’是c的子类,并且o’: InstanceTypeOf(c’),那么o’: InstanceTypeOf( c ). 仔细分析上面这条规则,我们可以在InstanceTypeOf的类型之间引入一个满足自反和传递性的子类型关系, 我们用<:符号来表示。(译者按:自反就是说, 对任何a, a 关系 a都成立,比如说,数学里的相等关系就是自反的。而传递性是说,如果a 关系 b, b 关系c, 就能推出a 关系c。 大于,小于等关系都是具备传递性的)

那么上面这条规则可以被拆成两条规则: 1. 对任何a: A, 如果 A <: B, 那么 a: B.

2. InstanceTypeOf(c’) <: InstanceTypeOf(c) 当且仅当 c’是c的子类

第一条规则被叫做Subsumption. 它是判断子类型(注意,是subtype, 不是subclass)的唯一标准。

第二条规则可以叫做subclassing-is-subtyping (子类就是子类型,绕嘴吧?) 一般来说,继承都是和subclassing相关的,所以这条规则也可以叫做:inheritance-is-subtyping (继承就是子类型)

所有的面向对象语言都支持subsumption (可以说,没有subsumption, 就不成为面向对象)。 大部分的基于类的面向对象语言也并不区分subclassing和subtyping. 但是,一些最新的面向对象语言则采取了把subtyping和subclassing分开的方法。也就是说,A是B的子类,但A类的对象却不可以当作B类的对象来使用。(译者按:有点象C++里的私有继承,但内容比它丰富)

好吧,关于区分subclassing和subtyping, 我们后面会讲到。

下面,让我们重新回头来看看这个procedure f. 在subsumption的情况下,下面这个代码的动态语义是什么呢?

Procedure f(x: InstanceTypeOf(cell)) is x.set(3); end;

f(myReCell);

当myReCell被当作InstanceTypeOf(cell)的对象传入f的时候,x.set(3)究竟是调用哪一个版本的set方法呢?是定义在cell中的那个set还是定义在reCell中的那个呢?

这时,我们有两种选择,

1. Static dispatch (按照编译时的类型来决定)

2. Dynamic dispatch (按照对象运行时真正类型来决定)

(译者按,熟悉C++的朋友们一定微笑了,这再简单不过了。) static dispatch没什么可说的。

dynamic dispatch却有一个有趣的属性。那就是,subsumption一定不能影响对象的状态。如果你在subsumption的时候,改变了这个对象的状态,比如象C++中的对象切片,那么动态

第 25 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

解析的方法就可能会失败。

好在,这个属性无论对语义,还是对效率,都是很有好处的。 (译者按,C++中的object slicing会把新的对象的vptr初始化成它自己类型的vtable指针, 所以不存在动态解析的问题。但实际上,对象切片根本不能叫做subsumption。

具体语言实现中,如C++, 虽然subsumption不会改变对象内部的状态,但指针的值却是可能会变化的。这也是一个让人讨厌的东西,但 C++ vtable的方案却只能这样。有一种变种的vtable方法,可以避免指针的变化,也更高效。我们会在另外的文章中阐述这种方法。)

5. 赛翁失马 (关于类型信息)

虽然subsumption并不改变对象的状态,在一些语言里(如Java), 它甚至没有任何运行时开销。但是,它却使我们丢掉了一些静态的类型信息。

比如说,我们有一个类型InstanceTypeOf(Object), 而Object类里没有定义任何属性和方法。我们又有一个类MyObject, 它继承自Object。那么当我们把MyObject的对象当作InstanceTypeOf(Object)类型来处理的时候,我们就得到了一个什么东西也没有的没用的空对象。

当然,如果我们考虑一个不那么极端的情况,比如说,Object类里面定义了一个方法f, 而MyObject对方法f做了重载,那么, 通过dynamic dispatch, 我们还是可以间接地操作MyObject中的属性和方法的。这也是面向对象设计和编程的典型方法。

从一个purist的角度看(译者按,很不幸,我就是一个purist), dynamic dispatch是唯一你应该用来操作已经被subsumption忘掉的属性和方法的东西。它优雅,安全,所有的荣耀都归于dynamic dispatch!!! (译者按,这句话是我说的)

不过,让purist们失望的是,大部分语言还是提供了一些在运行时检查对象类型,并从而操作被subsumption遗忘的属性和方法。这种方法一般被叫做RTTI(Run Time Type Identification)。如C++中的dynamic_cast, 或Java中的instanceof. 实事求是地说,RTTI是有用的。(译者按,典型的存在就是合理的强盗逻辑,气死我了!)。但因为一些理论上以及方法论上的原因,它被认为是破坏了面向对象的纯洁性。 首先,它破坏了抽象,使一些本来不应该被使用的方法和属性被不正确地使用。 其次,因为运行时类型的不确定性,它有效地把程序变得更脆弱。

第三点,也许是最重要的一点,它使你的程序缺乏扩展性。当你加入了一个新的类型时,你也许需要仔细阅读你的dynamic_cast或instanceof的代码,必要时改动它们,以保证这个新的类型的加入不会导致问题。而在这个过程中,编译器将不会给你任何帮助。

很多人一提到RTTI, 总是侧重于它的运行时的开销。但是,相比于方法论上的缺点,这点运行时的开销真是无足轻重的。

而在purist的框架中(译者按,吸一口气,目视远方,做深沉状),新的子类的加入并不需要改动已有的代码。

这是一个非常好的优点,尤其是当你并不拥有全部源代码时。

总的来说,虽然RTTI (也叫type case)似乎是不可避免的一种特性,但因为它的方法论上的一些缺点,它必须被非常谨慎的使用。今天面向对象语言的类型系统中的很多东西就是产生于避免RTTI的各种努力。

比如有些复杂的类型系统中可以在参数和返回值上使用Self类型来避免RTTI. 这点我们后面会介绍到。

6.协变,反协变和压根儿不变 (Covarance, Contravariance and Invariance)

在下面的几个小节里,我们来介绍一种避免RTTI的类型技术。在此之前,我们先来介绍“协变”,“反协变”和“压根儿不变”的概念。 协变

首先,让我们来看一个Pair类型: A*B

第 26 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

这个类型支持一个getA()的操作以返回这个Pair中的A元素。

给定一个A’ <: A, 那么,我们可以说A’*B <: A*B。 为什么呢?我们可以用Subsumption的属性加以证明:

假设我们有一个A’*B类型的对象a’*b, 这里,a’:A’, b:B, a’*b <: A’*B

那么,因为,A’ <: A, 从subsumption, 我们可以知道a’:A, getA():A 所以, a’*b<: A*B 这样,我们就定义A*B这个类型对于A是协变的。 同理,我们也可以证明A*B对于B也是协变的。 正规一点说,Covariance是这样定义的:

给定L(T), 这里,类型L是通过类型T组合成的。那么,

如果 T1 <: T2 能够推出 L(T1) <: L(T2), 那么我们就说L是对T协变的。 反协变

请看一个函数: A f(B b); (用functional language 的定义也许更简洁, 即f: B->A) 那么,给定一个B’ <: B, 在B->A 和 B’->A之间有什么样的subtype关系呢? 可以证明,B->A <: B’->A 。 基于篇幅,我们不再做推导。

所以,函数的参数类型是反协变的。

Contravariance的正规点的定义是这样的:

给定L(T), 这里,类型L是通过类型T组合成的。那么,

如果 T1 <: T2 能够推出 L(T2) <: L(T1), 那么我们就说L是对T反协变的。 同样,可以证明,函数的返回类型是协变的。 压根儿不变

那么我们再考虑函数g: A->A

这里,A既出现在参数的位置,又出现在返回的位置,可以证明,它既不是协变的,也不是反协变的。

对于这种既不是协变的,也不是反协变的情况,我们称之为Invariance (译者按:“压根儿不变”是我编的,这么老土的翻译,各位不必当真)

值得注意的是,对于第一个例子中的Pair类型,如果我们支持setA(A), 那么,Pair就变成Invariance了。

7.方法特化 (Method Specialization)

在我们前面对subclass的讨论中,我们采取了一种最简单的override的规则,那就是,overriding的方法必须和overriden的方法有相同的signature. 但是,从类型安全的角度来说,这并不是必须的。应用我们前面讨论的协变和反协变的知识,我们完全可以让方法的返回类型协变,让方法的参数类型反协变。 这样,只要A <: A’, B’ <: B, 下面的代码就是合法的: class c is

method m(x:A):B is … end;

method m1(x1:A1):B1 is … end; end;

subclass c’ of c is

override m(x: A’):B’ is … end; end;

我们暂时不允许属性的协变。因为只有immutable的属性才是协变的。允许对属性的修改使得属性都是invariant的。

特殊变量self这里有一个有趣的属性,它是一个参数,但它却是协变的。这种特殊特性是由于self变量只能隐式地由编译器传入,所以避免了协变参数的不安全性。

还有一点有趣的地方是,上面的协变发生在override的时候,也就是,子类要改写父类的方法的时候。但是,在继承时,参数和返回类型的变化规律就又是另一回事了。

第 27 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

比如说,下面这个例子:

class c is

method m(x:A):B is … end;

method m1(x1:A1):B1 is … end; end;

subclass c’ of c is

inherit m(x: A’):B’;

//这里,方法m的代码被继承,子类只是重定义方法m的接口signature end;

那么,这里,参数就是协变的,而返回类型却是反协变的了。 这里,从另一个侧面,我们看到了subtyping (通过override), 和subclassing (通过inheritance) 的本质上的区别。

8. Self类型的特化 (Self Type Specialization)

方法特化允许你灵活地在子类中继承或改写父类的方法时改变类型。 除此之外,我们也许还需要另一种灵活性。考虑下面的代码: class c is

method getSelf(): InstanceTypeOf(c) is return self; end; end;

subclass c’ of c is

var y: Integer := 0; end;

InstanceTypeOf(c’) x := (new c’).getSelf();

这里,最后一句代码是非法的,因为getSelf()的返回类型是InstanceTypeOf(c), 而x的类型是InstanceTypeOf(c’).

当然,子类c’可以重载getSelf()方法, 返回类型InstanceTypeOf(c’): subclass c’ of c is

var y: Integer := 0;

override getSelf(): InstanceTypeOf(c’) is return self; end; end;

这样,因为方法的返回类型是协变的,并且特殊变量self (译者按,就是C++/Java中的this)不论是在继承还是重载中都是协变的, 所以以上的子类定义是可行的。

但是,这要求每个子类都要重载这个方法。而且,如果某些返回self的方法想要隐藏一些逻辑的话,这种重载也是不可能的。比如: class c is

method changeAndReturn(): InstanceTypeOf(c) is

…//做一些更新操作。并且对子类隐藏逻辑。 return self; end; end;

subclass c’ of c is

var y: Integer := 0;

override changeAndReturn (): InstanceTypeOf(c’) is return super.changeAndReturn(); end; end;

第 28 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

这里这个子类c’的定义就是不成立的, 因为super.changeAndReturn()返回的是

InstanceTypeOf(c).

那么,有没有方法可以使子类c’继承的方法自然地返回InstanceTypeOf(c’)呢?这样一来,因为我们没有被迫丢失任何类型信息,RTTI就能够被避免。

这种考虑自然而然地引出了一种新的类型:Self类型。与self变量相似,Self类型代表的是这个对象的运行时真正类型。只有self变量是Self类型的。因为self变量的特殊协变特性,这样的类型是安全的。使用Self类型, 以上的例子可以被改写成: class c is

method getSelf(): Self is return self; end; end;

subclass c’ of c is var y: Integer := 0; end;

InstanceTypeOf(c’) x := (new c’).getSelf();

这时,最后一句就合法了,因为现在(new c’).getSelf()的返回类型是InstanceTypeOf(c’)了。 除了方法的返回类型,我们也可以把属性定义为Self类型,为了保证类型的安全,这样的属性只能用self或其它Self类型的值进行初始化或更新。也就是说,如果在class c中定义了一个Self类型的属性,你不能用一个InstanceTypeOf(c)的变量来初始化或更新它。 对典型的基于类的面向对象语言做如上所述的扩展是可行的,而且是没有任何副作用的(除了会使类型检查系统稍微复杂一些)。它使强类型面向对象语言的表达能力大大增强。并且有效地防止了类型信息的不必要丢失。

很自然地,读者也许会想到把Self类型用于方法的参数。Eiffel就是这样做的。但不幸的是,参数对于重载来说却是contravariant的,就象我们前面所说明的那样。重载时,类型泛化是可以的,但特化却是不安全的。

不过,在基于类的面向对象领域里,对参数使用Self类型还是被广泛研究并使用的。我们会在后面在介绍相关的技术。

下章预告:

对象类型,泛型技术,分离subclassing和subtyping, 对象协议(object protocol).

软件设计师知识点:面向对象语言概论(三)

传统的基于类的面向对象语言的一个主要特点就是inheritance, subclassing和subtyping之间的密不可分的联系。很多的面向对象语言的语法,概念,就是从这三者而来的。比如说,通过subclassing, 你可以继承父类的一些方法,而同时你又可以在子类中改写父类的方法。这个改写过的方法,通过subtyping, subsumption, 又可以从一个类型是父类的对象去调用。 但是,inheritance, subclassing, subtyping这三者并不是永远和睦相处的。在一些场合,这三者之间的纠缠不清会妨碍到通过继承或泛型得到的代码重用。因此,人们开始注意到把这三者分离开来的可能性。区分subclassing和subtyping已经很常见了。而其它的一些方法还处于研究的阶段。这一章我们将介绍这样一些方法。

一,对象类型

在早期的面向对象语言中(如Simula), 类型的定义是和方法的实现是混合在一起的。这种方式违反了我们今天已经被广泛认识到的把实现和规范(Specification) 分离的原则。这种分离得原则在开发是团队进行的时候尤其显得重要。

第 29 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

更近期一些的语言,通过引入不依赖于实现的对象类型来区分实现和规范。Modula-3以及

其它如Java等的支持class和interface的语言都是采用的这种技术。

在本书中,我们开始引入InstanceTypeOf(cell)时,它代表的概念相当有限。看上去,它似乎只表示用new cell生成的对象的类型,于是,我们并不能用它来表示从其它类new出来的对象。但后来,当我们引入了subclassing, method overriding, subsumption和dynamic dispatch之后,事情变得不那么简单了。我们的InstanceTypeOf(cell)已经可以用来表示从cell的子类new出来的对象,这些对象可以包括不是cell类定义的属性和方法。

如此看来,让InstanceTypeOf(cell)依赖于一个具体的类似乎是不合理的。实际上,一个InstanceTypeOf(cell)类型的对象不一定会跟class cell扯上任何关系。

它和cell类的唯一共同之处只是它具有了所有cell类定义的方法的签名(signature). 基于这种考虑,我们可以引入对象类型的语法: 针对cell类和reCell类的定义: class cell is

var contents: Integer :=0; method get(): Integer is return self.contents; end;

method set(n:Integer) is self.contents := n; end; end;

Subclass reCell of cell is Var backup: Integer: = 0; Override set (n: Integer) is self.backup:= self.contents; super.set (n); End;

Method restore () is

self.contents:= self.backup; End; End;

我们可以给出这样的对象类型定义: Object Type Cell is Var contents: Integer; Method get (): Integer; Method set (n: Integer); End;

Object Type ReCell is Var contents: Integer; Var backup: Integer; Method get (): Integer Method set (n: Integer); Method restore (); end;

这两个类型的定义包括了所有cell类和reCell类定义的属性和方法的类型,但却并不包括实现。这样,它们就可以被当作与实现细节无关的的接口以实现规范和实现的分离。两个完全无关的类c和c’, 可以具有相同的类型Cell, 而Cell类型的使用者不必关心它使用的是c类还是c’类。 注意,我们还可以加入额外的类似继承的语法来避免在ReCell里重写Cell里的方法签名。但

第 30 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

那只是小节罢了。

二,分离Subclassing和Subtyping.

在我们上一章的讨论中,subtype的关系是建立在subclass关系的基础上的。但如果我们想要让type独立于class, 那么我们也需要定义独立于subclass的subtype.

在定义subtype时,我们又面临着几种选择:subtype是由类型的组成结构决定的呢?还是由名字决定呢?

由类型的组成结构决定的subtype是这样的:如果类型一具有了类型二的所有需要具备的属性和方法,我们就说类型一是类型二的subtype. 由类型名字决定的subtype是这样的:只有当类型一具有了类型二的所有需要具备的属性和方法, 并且类型一被明确声明为类型二的subtype时,我们才认可这种关系。 而如果我们的选择是一,那么那些属性和方法是subtype所必需具备的呢?哪些是可有可无的呢?

由组成结构决定的subtype能够在分布式环境和object persistence系统下进行类型匹配(译者注:对这点,我也不甚明了。看来,纸造得还是不够)。缺点是,如果两个类型碰巧具有了相同的结构,但实际上却风马牛不相及,那就会造成错误。不过,这种错误是可以用一些技术来避免的。

相比之下,基于名字的subtype不容易精确定义,而且也不支持基于结构的subtype.

(译者按,这里,我无论如何和作者找不到同感。基于结构的subtype的缺点是一目了然,不过完美的避免的方法我却看不出来。而基于名字的subtype为什么就不能精确定义呢?C++/Java/C#, 所有流行的OO语言都只支持基于名字的subtype, 也没有发现有什么不够灵活的地方。需要在不同名字但类似结构的类型之间架桥的话,adapter完全可以胜任嘛!) 目前,我们可以先定义一个简单的基于结构的subtype关系: 对两个类型O和O’,

O’ <: O 当 O’ 具有所有O类型的成员。O’可以有多于O的成员。 例如:ReCell <: Cell.

为了简明,这个定义没有考虑到方法的特化。

另外,当类型定义有递归存在的时候(类似于链表的定义),对subtype的定义需要额外地加小心。我们会在第九章及之后章节讲到递归的时候再详细说明。(译者按:第九章啊?饶了我吧!想累死我啊?)

因为我们不关心成员的顺序,这种subtype的定义自动地就支持多重的subtype.

比如说:

ObjectType ReInteger is Var contents: Integer; Var backup: Integer; Method restore (); End;

那么,我们就有如下的subtype的关系: ReCell <: Cell

ReCell <: ReInteger

(译者按,作者的例子中没有考虑到象interface不能包含数据域这样的细节。实际上,如果我们支持对数据域的override, 而不支持shadowing -- 作者的基于结构的subtype语义确实隐含着这样的逻辑— 那么,interface里包含不包含数据域就无关紧要了,因为令人头疼的名字冲突问题已经不存在了) 从这个定义,我们可以得出:

如果c’是c的子类, 那么ObjectTypeOf(c’) <: ObjectTypeOf(c) 注意,这个定义的逆命题并不成立,也就是说:

第 31 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

即使c’和c之间没有subclass的关系,只要它们所定义的成员符合了我们subtype的定义,

ObjectTypeOf(c’) <: ObjectTypeOf(c)仍然成立。

回过头再看看我们在前一章的subclass-is-subtyping:

InstanceTypeOf(c’) <: InstanceTypeOf(c) 当且仅当 c’是c的子类

在那个定义中,只有当c’是c的子类时,ObjectTypeOf(c’) <: ObjectTypeOf(c)才能成立。 相比之下,我们已经部分地把subclassing和subtyping分离开了。Subclassing仍然是subtyping, 但subtyping不再一定要求是subclassing了。我们把这种性质叫做“subclassing-implies-subtyping”而不是“subclass-is-subtyping”了。

三,泛型 (Type Parameters) 一般意义上来说,泛型是一种把相同的代码重用在不同的类型上的技术。它作为一个相对独立于其它面向对象特性的技术,在面向对象语言里已经变得越来越普遍了。我们这里之所以讨论泛型,一是因为泛型这种技术本身就很让人感兴趣,另外,也是因为泛型是一个被用来对付二元方法问题 (binary method problem) 的主要工具。

和subtyping共同使用,泛型可以用来解决一些在方法特化等场合由反协变带来的类型系统的困难。考虑这样一个例子:

我们有Person和Vegitarian两种类型,同时,我们有Vegitable和Food两种类型。而且,Vegitable <: Food.

ObjectType Person is …

method eat(food: Food); end;

ObjectType Vegetarian is …

method eat(food: Vegitable); end; 这里,从常识,我们知道一个Vegitarian是一个人。所以,我们希望可以有Vegetarian <: Person. 不幸的是,因为参数是反协变的,如果我们错误地认为Vegetarian <: Person, 根据subtype的subsumption原则,一个Vegetarian的对象就可以被当作Person来用。于是一个Vegetarian就可以错误地吃起肉来。

使用泛型技术,我们引入Type Operator (也就是,从一个类型导出另一个类型,概念上类似于对类型的函数)。

ObjectOperator PersonEating [F<: Food] is …

Method eats (food: F); End;

ObjectOperator Vegetarian Eating [F<: Vegetable] is …

Method eats (food: F); End;

这里使用的技术被称作Bounded Type Parameterization. (Trelli/Owl, Sather, Eiffel, PolyTOIL, Raptide以及Generic Java都支持Bounded Type Parameterization. 其它的语言,如C++, 只支持简单的没有类型约束的泛型) F是一个类型参数,它可以被实例化成一个具体的类型。 类似于变量的类型定义,一个bound如F<:Vegitable限制了F只能被Vegitable及其子类型所实例化。所以,VegitarianEating[Vegitable], VegitarianEating[Carrot]都是合法的类型。而VegitarianEating[Beef]就不是一个合法的类型。类型VegitarianEating[Vegitable]是VegitarianEating的一个实例,同时它等价于类型Vegitarian. (我们用的是基于结构的subtype) 于是,我们有:

第 32 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

对任意F<:Vegitable, VegitarianEating[F] <: PersonEating[F]

对于原来的Vegitarian类型,我们有:

Vegetarian = VegetarianEating[Vegetable] <: PersonEating[Vegitable] 这种关系,正确地表达了“一个素食者是一个吃蔬菜的人”的概念。

除了Bounded Type Parameterization之外,还有一种类似的方法也可以解决这个素食者的问题。这种方法被叫做:Bounded Abstract Type 请看这个定义: ObjectType Person is Type F<: Food; …

Var lunch: F;

Method eats (food: F); End;

ObjectType Vegetarian is Type F<: Vegitable; …

Var lunch: F;

Method eats (food: F); End;

这里,F<:Food的意思是,给定一个Person, 我们知道他能吃某种Food, 但我们不知道具体是哪一种。这个lunch的属性提供这个Person所吃的Food.

在创建Person对象时,我们可以先选定一个Food的subtype, 比如说,F=Dessert. 然后,用一个Dessert类型的变量赋给属性lunch. 最后再实现一个eat(food:Dessert)的方法。

这样,Vegetarian <: Person是安全的了。当你把一个Vegetarian当作一个Person处理时,这个Vegitarian可以安全地吃他自带的午餐,即使你不知道他吃的是肉还是菜。

这种方法的局限在于,Person, Vegitarian只能吃他们自带的午餐。你不能让他们吃买来的午餐。

软件设计师知识点:面向对象语言概论(四)

四,彻底划清界限(继续分离Subclassing和Subtyping)

在第二节我们讨论了部分分离Subclassing和subtyping的方法,即subclassing-implies-subtyping. 现今的许多面向对象语言,如Java, C#都是采用了这种技术。除此之外,还有一种进一步分离Subclassing和subtyping的方法。这种被称作inheritance-is-not-subtyping的方法通过完全割裂subclassing和subtyping之间的联系而在更大程度上方便了代码的重用。

它的产生很大程度上是由于人们想要使用在反协变位置上的Self类型 (如Self类型的参数)。当然,增大继承的能力的代价是subsumption的灵活性降低了。当Self类型出现在反协变的位置上时,subclass不再意味着subtype, 因此,subsumption也就不存在了。 下面请考虑这样两个类型: ObjectType Max is var n: Integer;

method max(other:Max): Max; end;

ObjectType MinMax is var n: Integer;

method max(other:MinMax): MinMax; method min(other:MinMax): MinMax;

第 33 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

end;

再考虑两个类: class MaxClass is var n:Integer :=0;

method max(other: Self): Self is

if self.n > other.n then return self else return other end; end; end;

subclass MinMaxClass of MaxClass is method min(other: Self): Self is

if self.n < other.n then return self else return other end; end; end;

方法min和max是二元的,因为它操作两个对象:self和other. other的类型是一个出现在反协变位置上的Self类型。 注意,方法max有一个反协变的参数类型Self, 并且它被从类MaxClass继承到了MinMaxClass. 很直观地,类MaxClass对应着类型Max;类MinMaxClass对应着类型MinMax. 为了精确地表示这种对应关系,我们必须针对包含使用Self类型的成员的类重新定义ObjectTypeOf,以便得到ObjectTypeOf(MaxClass) = Max, ObjectTypeOf(MinMaxClass) = MinMax。

为了使以上的等式成立,我们把类中的Self类型映射到ObjectType中的类型名称本身。我们同时让Self类型在继承的时候特化。

在本例中,当我们映射MinMaxClass的类型时,我们把继承来的max方法中的Self类型映射到MinMax类型。而对MaxClass中max方法的Self类型,我们使用Max类型。

如此,我们可以得到,任何MaxClass生成的对象,都具备Max类型。而任何MinMaxClass生成的对象都具备MinMax类型。

虽然MinMaxClass是MaxClass的子类,但这里MinMax却不是Max的子类型(subtype). 举个例子,如果我们假设subtype在这种情况下成立,那么,对以下的这个类: subclass MinMaxClass’ of MinMaxClass is override max(other: Self): Self is

if other.min(self) = other then return self else return other end; end; end;

根据我们对Self类型的映射规则和基于结构的subtype规则,我们知道,ObjectTypeOf(MinMaxClass’) = MinMax, 所以,对任何MinMaxClass’生成的对象mm’ ,我们可以知道mm’ : MinMax.

而如果MinMax <: Max成立,根据subsumption, 我们就能推出mm’ : Max.

于是当我们调用mm’.max(m)的时候,m可以是任何Max类型的对象。但是,当max的方法体调用other.min(self)的时候,如果这个other不具有min方法,这个方法就会失败。 由此可见,MinMax <: Max并不成立。

子类(subclass) 在使用反协变的Self类型时就不再具有subtype的性质了。

五,对象协议 (Object Protocol)

从上一节的讨论,我们看到对使用反协变Self类型的类,subclass不再是subtype了。这是一个令人失望的结果,毕竟很多激动人心的面向对象的优点是通过subtype, subsumption来实现的。

不过,幸运的是,虽然失去了subtype, 我们还是可以从中挖掘出来一些可以作为补偿的有用的东西的。只不过,不象subtype, 我们不能享受subsumption了。

第 34 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

下面就让我们来研究这种新的关系。

在第四节的MinMax的例子中,subtype不再成立;简单地使用泛型,引入

ObjectOperator P*M <: Max+ is … end; 也似乎没有什么用。P[Max]虽然成立,但P[MinMax]却是不合法的,因为MinMax <: Max不成立。

但是,直观上看,任何支持MinMax这种协议的对象,也支持Max协议的 (虽然我们还不知道这个“协议”到底是个什么东西)。于是,似乎隐隐约约地又一个叫做“子协议”(subprotocol)的家伙在向我们招手了。

为了发现这个子协议的关系,让我们先定义两个type operator (还记得吗?就是作用在类型上的函数):

ObjectOperator MaxProtocol[X] is var n: Integer;

method max(other: X) :X; end;

ObjectOperator MinMaxProtocol[X] is var n:Integer;

method max(other: X):X; method min(other: X):X; end;

这样,Max = MaxProtocol[Max], MinMax = MinMaxProtocol[MinMax] 更一般地说,我们可以定义: 什么 = 什么-Protocol[什么]

还记得lamda-calculus里的fixpoint吗?给定一个函数F, F(fixpoint(F)) = fixpoint(F)

而在我们这个子协议的type operator里,如果我们认为type operator是作用于类型的函数的话, 那么这个“什么”,就是“什么-Protocol”函数的fixpoint啊! 也就是说:

什么= fixpoint (什么-Protocol).

除了以上的fixpoint的性质,我们还发现了存在于Max和MinMax之间的关系。

首先,MinMax是MaxProtocol的一个post-fixpoint,即: MinMax <: MaxProtocol[MinMax] 其次,我们可以看出:

MinMaxProtocol[Max] <: MaxProtocol[Max]

MinMaxProtocol[MinMax] <: MaxProtocol[MinMax]

最后,如果我们用<::来表示一个更高阶的子类型关系: P <:: P’ 当且仅当 P*T+ <: P’*T+

那么,MinMaxProtocol <:: MaxProtocol.

对于子协议的定义,我们可以采取上面的<::的定义,即:

如果S-Protocol<::T-Protocol, 那么我们称类型S和类型T之间是子协议关系。 (1) 我们也可以不用这个高阶的关系,仍然使用<:这个subtype的关系:

如果S<:T-Protocol[S], 那么我们称类型S和类型T之间是子协议关系。 (2)

其实,第一个定义似乎更直观一点,它更明确地显示出子协议关系是作用于类型上的函数(type operator)之间的关系,而不是类型之间的关系。

使用泛型技术,如果我们的某一个类型需要一个实现MaxProtocol的类型来实例化的话,我们可以采用下面两种方法中的一种:

ObjectOperator P1*X <: MaxProtocol*X++ is … end; (1) ObjectOperator P2*P <:: MaxProtocol+ is … end; (2)

这两种方法在表达能力上是相同的。第一种方法叫做F-bounded parameterization. (译者按,Generic Java据说就采用了这个方法);第二种方法叫做 higher-order bounded

第 35 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

parameterization.

对于具体语言的实现,为了方便,我们可以隐藏这个type operator. 语法上可以直接对类型支持subprotocol的关系(用<#来表示)。 对我们的MinMax的例子来说,我们就有: MinMax <# Max.

(译者按,绕了一大圈,什么fixpoint啊,post-fixpoint啊,什么高阶关系啦,希望没把你绕晕。其实,你只需要记住MinMax <# Max, 就八九不离十了,呵呵)

<#这个关系并不具有subsumption的性质,所以,你不能指望从它身上得到传统OO里面的多态。但是,与泛型相结合,它却是非常有用的。

比如说,我们可以对我们的所有你用来当作参数传给我的基于GP的快速排序模板函数给出这样的约束:用来实例化这个模板函数的的类型必须支持Comparable协议。

(译者按,使用它对加强C++中的模板的类型安全会很有用。其实,对使用gp的程序来说,也许子协议约束比子类型约束更合理。子类型的sumbsumption要求多态,即dynamic dispatch。但很多时候,我们并不一定需要类型参数支持多态。

思考题: 1. Java是支持Covariant的Array的。你可以把一个String[] 类型的对象当作一个Object[]类型来使用。

那么,Java的covariant array是类型安全的吗?为什么?

2. 大家都知道经典的矩形和正方形之间的类型关系吧?在支持get, set的正方形和矩形之间,并不存在subtype的关系,这是因为subsumption对get或set操作是不安全的。但是,是否正方形和矩形之间就不可能有subtype的关系呢?如果矩形的类型只支持get, 结果会是什么?如果正方形只支持set, 结果又是什么呢?

软件设计师下午试题初识

导读:软件设计师下午试题初识:1、分值分布,2、考试题目数量,3、考点总结。 考试方式:根据题目描述完成程序填空。 随着模块化试题的发展,软件设计师的下午试题题型基本固定,重点突出,便于考生有针对性地复习。

为能顺利通过考试,现在我们从以下几个方面来初步认识软件设计师下午试题中我们应该要了解和掌握的内容。

1、分值分布:软件设计师下午试题总分75分,每题15分,要求考生应答五道试题。其中前四题为必做题,占据60分,后面几题由考生根据自己的情况选做一题,合计75分。

2、考试题目数量:根据考试大纲要求,要求考生掌握C语言和C++、Java中的一种面向对象的程序语言。往年必做题有四道题,选做题有三道题,分别为C语言题、C++题和Java题,整个卷面共七道题。由于考试中许多考生在选做题中只选C语言题应答,对不会或不熟C++和Java语言的考生来说,一样可以应考,这与软件设计师考试大纲的要求是相背离的。因此,2010年5月软件设计师下午试题中,必做题数量不变,选做题里去掉了C语言题,即选做题为二道题,整个卷面共六道题。这样,考生在选做题中就只能在C++和Java中选择一题来作答,达到了考试大纲所要求的掌握一门面向对象的程序设计语言目的。

3、考点总结:从历届考题来看,考点如下表所示 题型 题号 考点 必做题 1 数据流图 第 36 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

2 3 4 5 6 选做题 7 数据库题 UML C语言程序填空 C语言程序填空(2010年5月取消) C++程序填空 Java程序填空 第一题:数据流图

数据流图简称DFD图。是结构化分析方法(SA)中用于表示系统逻辑模型的一种工具。要求考生掌握DFD图的基本成分:数据流、加工、数据存储及外部实体。

考试方式:根据题目描述判断DFD图中的实体,找出错误的数据流,补充缺失的数据流。

第二题:数据库题

根据软件设计师考试大纲要求,考生须掌握给定一个实际的应用问题如何设计E-R模型,如何将E-R模型转换成关系模式,确定联系类型、主键、候选键、外键,判断关系模式规范化的程度;掌握给定一个实际的应用问题如何用SQL进行数据定义(创建表、视图)、完整性定义及权限定义,掌握常用数据库的访问方法。希赛教育的模拟试题就不同的考点进行了收集。

考试方式:根据题目描述完成补充图形、填空、简答等形式。

第三题:UML

UML统一建模语言是面向对象软件的标准化建模语言。它是一种富有表达力的语言,可以描述开发所需要的各种视图,然后以此为基础装配系统。 在软件设计师下午试题中,要求考生掌握UML的基本概念与作用以及UML提供的9种图的表示与应用:类图、对象图、用例图、序列图、协作图、状态图、活动图、构件图和部署图。希赛教育软考学院针对不同的UML图编制了多套的模拟试题供学员学习。

考试方式:根据题目描述判断UML图中各元素所代表的事物,元素间的关系。

第四题和第五题:C语言程序填空

C语言是考试大纲要求考生必须掌握的程序语言,要求考生用C语言实现常用的数据结构与算法及应用程序。第五题与第六、第七题一起构成选答题。2010年5月的考试取消了C语言选答题。希赛教育软考学院的模拟试题中提供各种常用数据结构(线性表、栈、队列、串、数组、矩阵、数和图)以及常用算法(排序、查找、字符串、递归算法)练习和分析。

考试方式:根据题目描述程序的功能完成程序填空。

第六题与第七题:C++程序填空和Java程序填空

根据软件设计师考试大纲要求,考生须掌握一种面向对象的程序设计语言:C++或者Java,第六题与第七题由考生从中选择一道来应答,两题都答则选题号小的为有效答题。通常这两道题的题目背景是相同的,只是要求考生分别用C++和Java语言来实现常见的设计模式及应用程序。希赛教育软考学院研发中心组编的《软件设计师考试冲刺指南》中有设计模式的相关描述。

软件设计师试题疑难解答(1):ASPJSP

第 37 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

1.学习JSP需要如何开始?

答:要学习JSP编程,首先需要在本机搭建JSP页面的调试运行环境,然后再开始学习JSP语法和JSP页面的编写方法。 JSP的运行环境需要Java Runtime Environment和相应的JSP服务器,下面以windows平台为例,说明运行环境的搭建方法。 所需软件:

① 在 http://java.sun.com/products/jdk/1.2/处下载JDK(Java 2 SDK Standard Edition v 1.3,j2sdk1_3_0-win.exe)。 ② 下载JSP的服务器:http://jakarta.apache.org/builds/jakarta-tomcat-4.0/release/v4.0-b7/jakarta-tomcat-4.0-b7.zip 安装软件: (1)安装JDK ① 使用缺省配置安装j2sdk1_3_0-win.exe,JDK的缺省安装目录为C:\\jdk1.3 JRE的缺省安装目录为C:\\Program Files\\JavaSoft\\JRE\\1.3。 ② 然后修改AUTOEXEC.BAT文件,以设置修改系统环境参数: PATH=%PATH%;c:\\jdk1.3\\bin set CLASSPATH=c:\\jdk1.3\\lib\\tools.jar;c:\\jdk1.3\\lib\\dt.jar; 最后打开注册表编辑器,将键名: HKLM\\Software\\JavaSoft\\Java 运行时环境 改为:HKLM\\Software\\JavaSoft\\Java Runtime Environment (2)安装Tomcat ① 将jakarta-tomcat-4.0-b7.zip解压缩到C:\\jakarta-tomcat目录下 进入c:\\jakarta-tomca\\bin目录,找到startup.bat批处理文件,加入以下两行:start set tomcat_home=c:\\jakarta-tomcat set java_home=c:\\jdk1.3 ② 双击startup.bat启动tomcat服务器 这时,会出现一个名为Catalina的窗口,并有一些初始化信息,证明tomcat运行成功。 验证运行环境: 在浏览器上输入http://localhost:8080 如果能看到Tomcat Version 4.0这一页就表示Tomcat安装成功了。 上面有一些jsp和servlet的例子,至此jsp环境搭建完成。 注意Catalina窗口不能关掉,否则tomcat服务器停止服务。

2、目前的动态网页开发工具都有哪些,各有什么优缺点?

答:目前常用的动态网页开发工具主要有:ASP、PHP、JSP和微软即将推出的ASP.NET。 ASP主要运行在windows NT平台,其WEB服务器主要是IIS,是目前使用较多的一种开发工具,能胜任各种规模的网站开发,支持利用web控件和第三方控件来加强开发能力。 PHP是Personal Home Page的简写,主要适用于中小型动态网站的开发。与ASP相比,支持windows平台、Linux和Unix平台,且在Linux或Unix平台,运行速度和性能比ASP好,PHP在Linux或Unix平台下表现更为出色,是Unix平台的最佳选择,其数据库最佳搭档为mysql,当然通过ODBC也可访问其它符合ODBC标准的数据库。 JSP是一个比较优秀的动网开发工具,其运行速度比ASP和PHP都快,采取的是编译运行机制,即页面在第一次被请求时,系统会将其进行编译成中间代码,以后再访问该页面时,实际访问的是编译后的中间代码,因此运行速度较快,是一个比较看好的web开发工具。 ASP.NET是ASP的新一代动网开发工具,运行机制与JSP相似,运行速度也与JSP不分上下,也是最有前途的开发工具,目前微软公司在6月份已推出了其beta2测试版。在windows 2000 Server上,只要安装Net Framework Beta 2 开发包软件,即可让windows 2000 Server支持用asp.net所开发的网页,该网页的扩展名为aspx。安装该开发包后,windows 2000 Server原有的对asp的解析能力不受影响,即此时的windows 2000 server同时具备了对asp和aspx的解析能力。 注:Net Framework Beta 2 开发包下载地址 http://download.microsoft.com/download/VisualStudioNET/Trial/2.0/W982KMeXP/EN-US/setup.exe

3.ASP如何存取mysql数据库?

答:首在安装mysql数据为,然后安装mysql的ODBC驱动程序(可从mysql主页下载)。注意访问时,要启动mysql服务器。 在ASP中,就可利用如下链接字符串,实现对mysql数据库及数据表的访问。 constr= \要访问的数据库名称\

第 38 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

软件设计师试题疑难解答(2):选择排序

问题1

本程序从键盘输入N(0 # define N 100 void main()

{ int a[N],n,i,j,ind,c1,c2; do{

printf(“输入n(0

}while(n<=0|| n>99 ); 空1 printf(“输入数组元素:\\n”); for(i=0;i

for(c1=1,j=I+1;j

if(a[j]==a[I]) c1=c1+1; 空2

if (c1>c2 空三||c1==c2&&a[I]>a[ind] {

c2==c1; ind=I;空四 } }

printf(“其中%d出现%d次\\n”,a*ind+, c2)空五; }

在这道题目中我认为C1,为数组元素下标,用来追踪数组元素;C2为数组元素出现的次数;所以空2中C1加1;那空三如何解释呢??a[ind]为原来找到的最大数,所以ind=I;既然要打印出最大数据出现的次数,那为什么空5为C2,不是C1呢??? 解答:

题目中C1是用来计算元素的出现次数的,如果出现了相同的则C1+1,直到最后一个元素。那么C2就是用来存储出现次数最多的元素出现的次数。所以空三的解释就是用C2来记录C1的最大值;

a[ind]为原来找到的最大数,所以ind=I;,也正因为如此,最后打印出最大数据出现的次数是C2;

问题2

关于选择排序:下面的选择排序的算法: void ss_sort(int e[], int n) { int i, j, k, t;

for(i=0; i< n-1; i++) {

for(k=i, j=i+1; je[j]) k=j; if(k!=i) {

t=e[i]; e[i]=e[k]; e[k]=t; } }

第 39 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

}

我在作题和理解算法的时候总是忘记了k=j;我觉得这好象没有意义,那去掉为什么不可以,能帮我解释k=j的含义吗?? 解答:

首先这个语句是不能去掉的,因为所有排序的判断都需要它。 if(e[k]>e[j]) k=j;的意思是如果有一个元素比e[k]小,那么就要把K的值更改为较小元素的下标,也就是j,更改过后就要判断

if(k!=i)是否成立,如果K的值变化就要做元素的顺序调整,否则就不变,所以针对这个算法,建议你看一下专门的数据结构的排序算法,弄清楚原理后再理解;

3.如何调试ASP页面? 答:当ASP页面在运行出错时,虽然浏览器会报告一些简单的错误信息,但信息太简约,一般仅提示出现HTTP 500号错误,即服务器内部错误。为此,在调试时,可在IIS管理器中打开服务器端的ASP脚本调试功能,其打开方法为:

应用程序调试,然后选中启用ASP服务器端脚本调试。?配置?主目录?打开IIS管理器

4.ASP、PHP和JSP有什么区别?

答:这三个都是用来开发动态网页的。彼此间的差异主要在于所使用的编程脚本不同,运行速度不同。ASP一般采用VBScript进行服务器端编程;PHP使用的是自身的脚本语言,很类似于C语言的语法,优点运行速度比ASP略快,支持跨平台运行;JSP的编程采用的是Java编程语言,运行速度很快,效率较快,支持跨平台运行。

软件设计师面向对象中的重要概念:接口

问:初学者。目前光看书只知道接口仅仅声明一些空的成员,这些成员必须在类中来实现,接口可继承。但我不明白既然接口的这些没有实际代码的成员还要在类中实现,那还要接口干什么,直接用类就可以了嘛,请高手明示,谢谢! 答:

类是一个一个的插头. 接口1 是 2线的插头 接口2 是 3线的插头

如果全世界有1000种插头和 2种接口. 如果你现在生产一个插座,你是对这2种\接口\做2种插座还是对1000种插头做1000种插座??????

显然是做2种,那么不实现这个接口的插头(不是2线或3线的),就不能察进你的插座. 表面看是一种自己束缚自己,其实是一种解放,正是有了这两种\接口\才有我们现在很方便地使用插座和插头,否则,那么多厂家,有人用7个脚的插头,有人用12个脚的,就算一样是3个脚吧,有人排成一条直线,那么你随时发现你找不到合适的插头或插座....每人都要准备成百上千的插座,累不?

UnderStand? 应该上面我这段比喻可以提供一小点你看书看不到的东西吧.

软件设计师面向对象知识点:思考面向对象是什么?

先考虑一个现实问题, 大家都熟悉的手机发短信. 来看看早期(A 大约是汇编语言时代),中期(B 结构化),现在(C 面向对象)三种思想下的不同实现.

我说的是思想, 因为虽然现在大家使用着面向对象的工具,但是大部分程序员的思想依然没

第 40 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

有面向对象. 比如现在我手下这群程序员里有面向对象分析和设计能力的也就一个..

用最面向对象java和C#也可以写出杂乱无章完全不面向对象甚至不结构化的程序.

注意到现在我们的手机号码分成移动和联通两种, 虽然对我们来说,不过是号码不一样收费不太一样,没多少区别,但是两家的短信接口可是完全不一样的.

假设程序要求 用户在界面上输入手机号码(TextBox1),输入一条短信内容(TextBox2),按确定(Button1),就可以把短信发到那个手机上

A 一步一步走,该干什么就干什么...看看伪代码: st***号码 = TextBox1.Text; st***内容 = TextBox2.Text;

int 第3位数字 = int.Parse(号码.Substring(2,1)); //把第3位取出来,用来判断是不是移动的手机 如 1390000000 就取出一个 9 if(第3位数字 > 3) { .... ....

....//这里是一堆长长的代码用来发送***的短信...省略,我们这里只说程序的思想..不涉及技术细节 } else { .... ...

...//又是一堆长长的代码用来发送***的短信 }

B 写一个库,定义出发送***短信的函数和发送***短信的函数,还有判断的函数,假设函数原型分别是

发送移动短信(st***手机号码,st***内容); 发送联通短信(st***手机号码,st***内容); bool 是否是移动号码(st***手机号码); 然后写程序如下:

if(是否是移动号码(TextBox1.Text))

发送移动短信(TextBox1.Text,TextBox2.Text); else

发送联通短信(TextBox1.Text,TextBox2.Text);

C 定义一个抽象接口 \短信接收者\由 \和 \两个类分别实现接口. 各自实现发送短信方法.

然后构造一个 \手机工厂\一时想不到好的名字,暂时叫这个吧) , 接收一个号码,返回一个 \短信接收者\接口(里面根据接收的参数,可能是***或***) 然后程序如下(一行..):

手机工厂.获取接受者(TextBox1.Text).发送(TextBox2.Text); 或写成这样清晰点:

st***号码 = TextBox1.Text; st***内容 = TextBox2.Text;

手机工厂.获取接受者(号码).发送(内容);

第 41 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

OK,对于上面3段伪代码 大家有什么想法? 第3种是不是看起来有点 爽? 也许把,也仅仅是看

起来那么一点爽,没什么大不了.

没错,面向对象是在大型的地方更能体现优势,一小堆是展现不出来的. 我们假设程序中一共有100个这样的地方(比如一个是发短信的,一个接短信的,一个打电话的,一个上网的.....) 那么对于A程序,很抱歉,非常要命,要在100个地方复制代码,复制100份,然后对其中99份做修改(或多或少,总要改点..)

B程序只是在每个调用的地方加几行,可以接受. C程序在调用点也是加1行,同样也可以接受.

这个时候,结构化和面向对象共同的优点体现出来了,复用性 (教科书中讲面向对象总是说说复用是面向对象比其他方法的优势,其实结构化本身就是可复用的)

A方法差不多该抛弃了........这就是结构化发展起来以后, 非结构化很快面临淘汰地步的原因,因为在软件稍微大点,就出麻烦,写写单片机小模块还行.

软件在一天天变大变复杂,仅仅是变大变复杂而已? 当然不是. 也变得多变. 用户的需求时时在变.软件也容易变,.

回到刚才的问题, 现在不是有小灵通么? 你又需要多一种类型,变成 小灵通\\移动\\联通 3种类型.

那么对于 A ,灾难发生....修改程序的成本不比重新做一个少.

对于B 需要去100个调用的地方多加一个if来判断,然后多加一个对应小灵通的函数. 修改量有点大,不过也不是不行,因为毕竟现在的工具发达,你可以查找--替换. 不过程序是需要测试的,你替换一个地方,就需要多测试一个地方,成本高.

对于C 多加一个实现 接口的 \小灵通\类 , 然后修改 \手机工厂\的 \获取接受者(st***号码)\一共2处,测试也只要再测试 这个新类 还有一个方法.

C 方法 面向对象的优势在这个时候体现出来了.

有人这个时候出来抗议了,如果程序写的多了,经验丰富了,有人会看出我上面那些假设的漏洞,就是B 并不是最好的结构化方法, 因为 其实有更好的用一个函数来实现判断类型 那样就跟 C 一样,只要改很少的地方了.

没错, 那样C和B又公平平等了,C还是没什么优势. 请注意2点 第一: \面向对象\不是指 面向对象 的 编程语法, 而是一种思想. 那样写其实 B 已经拿到了一点面向对象的思想了

只是封装在非面向对象的语法中. 第二 不面向对象的确可以写出低耦合的,高效的,可维护的,很牛逼的程序. 但是那是需要很高造诣的人来做的事. 因为没有类的封装性,名字空间的隔绝 还有全局性的变量在程序里走, 要靠程序员自己去避免这些\可以做,可以方便地做\却\会对未来维护带来灾难\的操作, 对程序员要求很高,你要自觉不用全局变量,就像以前自觉不 用goto语句....还要自觉把功能分好摆好, 需要的分析设计技术是很高的. 而写出同样质量的面向对象程序,只要略知道设计模式的人就都可以了. 这就是面向对象大行的原因之一. 有人说,面向对象就真的封装了?可重用了? 可是我看见很多C#和java程序错乱复杂, 根本拿不出一个 \块\出来用,你拿了 \块A\就调用到 \块B\非要把\块B\也拿来..然后又要

用到无关的C,D,E,F.....最后出来一大落,而且99.9999%是我不需要的,我就只需要那0.00001%而已....

这是现实,的确,至少我看见的代码里垃圾代码占多数(这里是指可以实现功能却很\有臭味\的代码), 这主要有一个很大的原因是写代码的人没有面向对象的思想,有的只是面向对象 工具包装的面向过程思想,而且连结构化都说不上. 不是面向对象的错.

差不多,有些人现在认同面向对象了,也知道这不是书上随便说的那些苦涩的概念了,不过还是不明白怎么个面向对象法. 我再换个话题说说,不说手机吧,

说衣服,服装厂生产衣服. 衣服有颜色,有大小,有款式.... 看看一个设计,在不同的人手里是什么不同的方法.

第 42 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

现在服装厂要 生产一批 蓝色的, 小号的, 女款的...的衣服...

A :

衣服 衣服1 = new 衣服(); 衣服1.颜色 = 兰; 衣服1.号码 = 小; 衣服1.款式 = 女式; .....

然后new 出好多件来.赋值好多下....

现在问题是突然说不要兰的了要红的, 哎哟....改啊改.... 当然你可以在循环里做这个,但是如果每件衣服除了颜色和款式一样, 大小是不同的又如何? 有个B想到了一个好的设计了.

定义一个衣服类, 然后把 大衣服 作为一个 子类,小衣服是另外一个子类. 那么方便了一些. 不过又有问题,如果再改需求.....要求大小跟男女固定的,颜色可以变,

难道又再定义出兰衣服类和红衣服类.....那还有完没完啊........依然不是好设计. C

面向对象有一个利器叫 \设计模式\学面向对象基本上这个是必修, 我们用用设计模式中的原型模式,构造出一个原型 假设是一件 大的男装, 然后通过Copy这个原型就可以

得到一批大的男装,然后给各种颜色就行. 如果是再变化,那么我们不需要什么变,只要再构造另外一个原型,然后用代码Copy这个原型,又可以试用新的变化了....

软件设计师面向对象知识点:面向对象系统的特性

面向对象系统最突出的特性就是封装性、继承性和多态性。衡量某一种程序设计语言,看它是否是面向对象的程序设计语言,主要看它是否具有这三种特性。在这一章中我们将对它们逐个地进行分析。 3.1 封 装 性

3.1.1 什么是封装

从字面上理解,封装就是将某事物包围起来,使外界不知道其实际内容。

在程序设计中,封装是指将一个数据和与这个数据有关的操作集合放在一起,形成一个能动的实体 ---- 对象,用户不必知道对象行为的实现细节,只需根据对象提供的外部特性接口访问对象即可。因此,从用户的观点来看,这些对象的行为就像包含在一个“黑匣子”里,是隐蔽的、看不见的。

从上面的叙述我们看出,封装应该具有下面几个条件:

①具有一个清楚的边界,对象的所有私有数据、内部程序(成员函数)细节都被固定在这个边界内。

②具有一个接口,这个接口描述了对象之间的相互作用、请求和响应,它就是消息。

③对象内部的实现代码受到封装壳的保护,其它对象不能直接修改本对象所拥有的数据和代码。

3.1.2 什么是协议

协议是一个对象对外服务的说明,它声明这个对象可以为外界做什么。它是由一个对象能够接受并且愿意接受的所有信息构成的对外接口。也就是说,请求对象进行操作的唯一途径

第 43 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

就是通过协议中提供的消息进行的。

例如,一个人有各种能力,其中有一部分能力他乐意向外界公布并对外界提供服务;还有部分能力只是有选择地向某些人宣布;还有一部分能力他不想让任何人知道,即使外人知道了他所具有的这部分能力,他也不向他提供服务。这里就存在一个协议的问题,我们可以将能够提供服务的那部分能力写到协议中去。

外界对象能够并且只能根据该对象发送协议中所提供的消息,请求该对象服务。即使一个对象可以完成某一功能,但它没有将该功能放入协议中去,外界对象依然不能请求它完成这一功能。协议实际上是一个对象所能接受的所有公有消息的集合。 下面是一个用C++语言所定义的对象类: class student{ private:

char * name; int mark; char *major;

vOid changemark(); protected: int getmark,(); public:

char *getname(); char *getmajor(); };

在上面所定义的学生对象类中,包含的数据内容有学生姓名、分数、专业。 它所包含的操作(所具有的功能)分为三种:

①处于私有段(private)的changemark,这是不向外界公开的功能,只供对象自己使用。

②处于保护段(protected)的getmark,这是只向部分外界宣布的功能,只对其派生类对象提供服务。

③处于公有段(public)的getname和getmajor,这是向所有外界公开的功能,它可以响应外界对象的请求,这些是属于协议的内容。

3.1.3 面向对象系统的封装性

面向对象系统的封装性是一种信息隐藏技术,它使系统设计员能够清楚地标明他们所提供的服务界面,用户和应用程序员则只看见对象提供的操作功能,看不到其中的数据或操作代码细节。

从用户或应用程序员的角度看,对象提供了一组服务,而服务的具体实现即对象的内部却被屏蔽封装着。

对象的这一封装机制的目的在于将对象的使用者与设计者分开,使用者不必知道对象行为实现的细节,只需用设计者提供的协议命令对象去做即可。 面向对象系统中的封装单位为对象,即主要指对对象的封装,该对象的特性是由它所属的类说明来描述。除去对象的封装以外,类概念本身也具有一种封装意义,它将数据和与这个数据有关的操作集合封装在一起,建立了一个定义良好的接口,这反映了抽象数据类型的思想。

3.2 继 承 性

3.2.1 继承的引入

继承是面向对象系统中的另一个重要的概念。在前面,我们讨论了类,这些类是孤立的,相互之间还没有建立关系,也就是说,这些类都处在同一级别上,是一种平坦结构。而这种没有相交关系的平坦结构限制了面向对象系统的设计,这是因为它不允许类之间实现信息共

第 44 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

享。在系统中有些对象,它们有一些相同但又有些差别,如果不允许类之间建立相交关系,

这些不同对象的相似之处就无法表现出来。

继承所表达的就是一种对象类之间的相交关系。它使得某类对象可以继承另外一类对象的特征和能力。

若类间具有继承关系,则它们之间应具有下列几个特性: ·类间具有共享特征(包括数据和程序代码的共享), ·类间具有细微的差别或新增部分(包括非共享的程序代码和数据); ·类间具有层次结构。

具体地讲,若类B继承类A时,则属于B中的对象便具有类A的一切性质(数据属性)和功能(操作)。我们称被继承类A为基类或父类,或超类,而称继承类B为A的派生类或子类。因此,要构造一个新类B,只需去继承一个与之有共同特征的基类A,再描述与基类不同的少量特征(即增加一些新的数据成员和成员函数)。于是,类B便由继承来的和新添加的两部分特征组成。

继承所具有的作用有两个方面:一方面可以减少代码冗余;另一方面可以通过协调性来减少相互之间的接口和界面。

3.2.2继承的分类

继承的分类可从下述两个方面考察。 1.从继承源上划分

即从系统研究的角度来分,继承分为单继承和多继承。例如一个人只能继承一个人的财产,这就是单继承。例如一个人既可以继承父母的财产,又可以继承其他亲属的财产;这就是多继承。

2.从继承内容上划分

继承可分为取代继承、包含继承、受限继承和特化继承。

(1)取代继承 例如徒弟从其师傅那里学到师傅的所有的技术,则在任何需要师傅的地方都可以由徒弟来代替,这就属于取代继承。

(2)包含继承 例如“水果”是一类对象,“苹果”是一种特殊的水果。“苹果”继承了“水果”的所有特征,任何一个苹果都是一个水果,这便是包含继承。即苹果包含了水果具有的所有特征。

(3)受限继承 例如,“鸵鸟”是一种特殊的鸟,它不能继承鸟会飞的特征,这就是受限继承。

(4)特化继承 例如,“工程师”是一类特殊的人,他们比一般人具有更多的特有信息,这就是特化继承。

从上面继承分类的两个方面可以看出,所有的继承关系都存在类与类之间,而且都具有两类不同的性质,一类是用来描述继承源的(单继承和多继承就属于此类);另一类是用来描述继承内容的(取代继承、包含继承、受限继承和特化继承就属于此类)。

3.2.3 继承与封装的关系

在面向对象系统中,有了封装机制以后,对象之间只能通过消息传递进行通讯;那么,继 承机制的引入是否削弱了对象概念的封装性,继承和封装是否矛盾。其实这两个概念并没有实质性的冲突,在面向对象系统中,封装性主要指的是对象的封装性,即将属于某一类的一个具体的对象封装起来,使其数据和操作成为一个整体。

在引入了继承机制的面向对象系统中,对象依然是封装得很好的实体,其它对象与它进行通讯的途径仍然只有一条,那就是发送消息。类机制是一种静态机制,不管是基类还是派生类,对于对象来说,它仍然是一个类的实例也许是基类的实例,也许是派生类的实例,因此继承机制的引入丝毫没有影响对象的封装性。

第 45 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

从另一角度看,继承和封装机制还具有一定的相似性,它们都是一种共享代码的手段。继承

是一种静态共享代码的手段,通过派生类对象的创建,可以接受某一消息启动其基类所定义的代码段,从而使基类和派生类共享了这一段代码。而封装机制所提供的是一种动态共享代码的手段,通过封装,我们可将一段代码定义在一个类中,在另一个类所定义的操作中,我们可以通过创建该类的实例,并向它发送消息而启动这一段代码,同样也达到了共享的目的。

3.2.4 继承与委托的关系

委托是面向对象设计中经常使用的一种方法。在面向对象系统中,每个操作元素都是一个对象,为了减少一个操作的实现代码,我们尽量使用向其它对象发送消息而不再重写代码,这就是委托的意义。这意味着在定义一个对象的操作时,要委托该操作所涉及的其它对象完成部分操作来实现。

继承和委托的相同点是,都具有节省代码的作用,继承定义的类可有继承其它类的能力;委托则是一个对象可以依赖其它对象为它完成某些操作。

但继承和委托又是性质不同的两种关系。继承是静态关系,在程序描述时建立,它的基本功能是将一些功能相关的对象进行特定归类表示,使得特殊类别的对象有继承较为一般类别对象的能力;而委托则是一种既可以静态定义也可以动态定义的更复杂的关系,它的基本功能是将一个对象的工作分配到与之相关的更特殊的对象上。

3.2.5 类的层次

在前面已经介绍了继承的概念,当一个类B从类A中派生出来,B类继承了A类的部分或全部属性,B类作为一个派生类,它又可以再派生新类,这样我们可以从某一个类派生出所需的任意多的类,这就形成了类的层次。 下面是C++语言中派生类的定义: class A{ // … };

class B : public A{ // … };

class C : publicB{ // … };

类B是从类A中派生出来的,也就是说A是B的基类,而且是直接基类,B是A的派生类;类C是从类B中派生出来的,也就是说B是C的直接基类,C是B的派生类。对于C类来讲,除去B是它的直接基类外,A也是它的基类,但是是间接基类。由此,A,B,C这三个类之间的继承关系就形成了一个类的层次。

类的层次关系可以清楚有效地表示现实世界中事物的分类问题。

3.2.6 单继承与多继承

根据我们已经介绍的继承的概念和类的层次,如图3.1所示即为类间的单继承关系。 从图中我们可以看出,B类和C类是A类的派生类,A类是B类和C类的基类;D类和E类是B类的派生类,B类是D类和E类的基类。由A,B,C,D,E所组成的是一种单继承的派生形式,即每个派生类只是继承了一个基类的特性。

使用单继承可以解决很多问题,但在不少场合,需要不同形式的继承才能解决问题,单继承就似乎显得无能为力了。例如,在基于位映象的显示器上,用户界面所提供的窗口、滚动条、尺寸框以及多种类型的按钮,假定所有这些都是通过类来支持的,假如要把所有这些类型合

第 46 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

并成一个新类型,这样,多继承的概念就产生了,所谓多继承就是在派生类中继承了不止一

个基类的属性。

D类是A类和B类的派生类,A类和B类均是D类的直接基类。E类是B类和C类的派生类,B类和C类均是E类的直接基类,F类是D类、E类和C类的派生类,D类、C类和E类均是F类的直接基类。A,B,C,D,E和F类形成了一个多继承的类层次。 多重继承的引入,使面向对象系统大大增加了模拟世界的能力。

3.2.7 面向对象系统的继承性

在面向对象系统中,引入继承机制后具有如下优点: ①能清晰体现相关类间的层次结构关系。

②能减小代码和数据的重复冗余度,大大增加程序的重用性。

③能通过增强一致性来减少模块间的接口和界面,大大增加程序的易维护性。 ④继承是能自动传播代码的有力工具。

⑤继承还是在一些比较一般的类的基础上构造、建立和扩充新类的最有效的手段。 在面向对象系统中,若没有引入继承的概念,所有的类就会变为一盘各自为政、彼此独立的散沙,每次软件开发就都要从“一无所有”开始。

在面向对象系统中,继承性不仅作用在对操作的继承,还作用在对数据内容的继承,即既具有结构特性的继承性,又具有行为特性的继承性。

在面向对象系统中,派生类是否可以访问基类的所有数据成员和函数成员呢?我们以C++为例来说明,在C++语言中,类的定义域分为三段:即私有段(private)、保护段

(protected)和公有段(public)。基类的成员若处在保护段和公有段中,派生类是可以访问的;若基类的成员处在私有段中,派生类是无权访问的。

3.3 多 态 性

多态性是面向对象系统中的又一重要特性,它描述的是同一个消息可以根据发送消息对象的不同采用多种不同的行为方式。

3.3.1 重载的概念 在面向对象系统中,重载的含义是指通过为函数和运算符创建附加定义而使它们的名字可以重载。也就是说相同名字的函数或运算符在不同的场合可以表现出不同的行为。 下面是一个C++语言中函数重载的例子: class number{ int i; float x; char s1; public:

int max(int a)(return a>i? a : i;)

float max(float b)(return b>x ? b: x;) char *max(char *c)

{ return strcmp(c,s1)>0 ? c : s1; } // … };

在这里重载了三个函数,均为max,它们的功能为将函数的参数分别与类中各私有数据比较大小。函数名相同,它们的差别在于函数参数的类型不同。

当有求最大值的消息发送时,到底是执行这三个函数中的哪一个,也就是说到底要表现出什么样的行为,这要看发送消息的对象是什么。通俗地讲在这里要看传递的函数参量是什么,根据参量来调用不同的同名函数,假如发送的消息为max(10),则执行第一个max函数,因

第 47 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

为其参量为整型的。

在定义函数重载时,函数名相同,但函数所带的参量的个数或类型必须有所区别,否则就会出现二义性。

在面向对象系统中除函数可以重载外,运算符也可以重载。

3.3.2 虚函数的概念

虚函数使用户在一个类等级中可以使用相同函数的多个版本,每一个版本均属于类等级中的不同的类,究竟使用的是哪一个特定的版本需要在运行中决定。

在C++语言中,虚函数在定义时,要在基类的此函数声明前加上关键字virtual,在派生类中可重新给出定义。虚函数的各个版本中,其返回值、函数参数的个数和类型必须是一致的。至于在程序执行过程中究竟运行的是基类的版本,还是某个派生类的版本,这要看当时发送此消息的对象是属于哪一类的。

关于在C++语言中虚函数如何使用,将在C++实践部分给出详细的叙述,这里不再 举例。

3.3.3 抽象类的概念

抽象类的作用在于将许多有关的类组织在一起,提供一个公共的基类,而那些被它组织在一起的具体的类由它派生出来。它刻划了公有行为的特征,并通过继承机制传送给它的派生类。

抽象类只描述与这类对象有关的协议和协议部分消息的部分实现,完整的实现留给它的派生类来具体完成。

抽象类是不能创建具体对象的类,即不能产生实例,只能建立它的派生类的对象。 在C++语言中,通过在类中声明纯虚函数的方法来定义抽象类。下面是一个简单的例子。 class shape{ int x,y; // … public:

void move(int,int);

virtual void rotate(int) = 0; //定义纯虚函数 virtual void draw(); //定义虚函数 };

class ab_circle:public shape{ int radius;

void rotate(int); void draw(); };

在类shape中存在纯虚函数rotate,所以shape为抽象类,ab_circle为它的派生类。我们不能建立shape类的对象,只能建立ab_circle类的对象。

3.3.4 面向对象系统的多态性

面向对象系统的多态性指的是,当不同的对象收到相同的消息时产生不同的动作。C++语言支持两种多态性:即编译时的多态性和运行时的多态性。编译时的多态性是通过使用重载来实现的,到底执行的哪个重载版本在编译时就可以知道,所以是相对静态的多态性。运行时的多态性是通过虚函数来实现的,到底运行的哪个函数版本,需要在运行时通过找出发送消息的对象来确定,编译器在编译时采用的是动态联编手段。

软件设计师面向对象知识点:面向对象方法简介

第 48 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

面向对象方法(Object-Oriented Method)是一种把面向对象的思想应用于软件开发过程中,指导开发活动的系统方法,简称OO (Object-Oriented)方法,是建立在“对象”概念基础上的方法学。对象是由数据和容许的操作组成的封装体,与客观实体有直接对应关系,一个对象类定义了具有相似性质的一组对象。而每继承性是对具有层次关系的类的属性和操作进行共享的一种方式。所谓面向对象就是基于对象概念,以对象为中心,以类和继承为构造机制,来认识、理解、刻画客观世界和设计、构建相应的软件系统。

面向对象方法作为一种新型的独具优越性的新方法正引起全世界越来越广泛的关注和高度的重视,它被誉为\研究高技术的好方法\,更是当前计算机界关心的重点。十多年来,在对OO方法如火如荼的研究热潮中,许多专家和学者预言:正象70年代结构化方法对计算机技术应用所产生的巨大影响和促进那样,90年代OO方法会强烈地影响、推动和促进一系列高技术的发展和多学科的综合。

一、面向对象方法的由来与发展 回顾历史可激励现在,以规划将来。

OO方法起源于面向对象的编程语言(简称为OOPL)。50年代后期,在用FORTRAN语言编写大型程序时,常出现变量名在程序不同部分发生冲突的问题。鉴于此,ALGOL语言的设计者在ALGOL60中采用了以\为标识的程序块,使块内变量名是局部的,以避免它们与程序中块外的同名变量相冲突。这是编程语言中首次提供封装(保护)的尝试。此后程序块结构广泛用于高级语言如Pascal 、Ada、C之中。

60年代中后期,Simula语言在ALGOL基础上研制开发,它将ALGOL的块结构概念向前发展一步,提出了对象的概念,并使用了类,也支持类继承。70年代,Smalltalk语言诞生,它取Simula的类为核心概念,它的很多内容借鉴于Lisp语言。由Xerox公司经过对Smautalk72、76持续不断的研究和改进之后,于1980年推出商品化的,它在系统设计中强调对象概念的统一,引入对象、对象类、方法、实例等概念和术语,采用动态联编和单继承机制。

从80年代起,人们基于以往巳提出的有关信息隐蔽和抽象数据类型等概念,以及由Modula2、Ada和Smalltalk和等语言所奠定的基础,再加上客观需求的推动,进行了大量的理论研究和实践探索,不同类型的面向对象语言(如:Object-c、Eiffel、c++、Java、Object-Pascal等)逐步地发展和建立起较完整的和雨后春笋般研制开发出来,OO方法的概念理论体系和实用的软件系统。

面向对象源出于Simula,真正的OOP由Smalltalk奠基。Smalltalk现在被认为是最纯的OOPL。

正是通过Smalltalk80的研制与推广应用,使人们注意到OO方法所具有的模块化、信息封装与隐蔽、抽象性、继承性、多样性等独特之处,这些优异特性为研制大型软件、提高软件可靠性、可重用性、可扩充性和可维护性提供了有效的手段和途径。

80年代以来,人们将面向对象的基本概念和运行机制运用到其它领域,获得了一系列相应领域的面向对象的技术。面向对象方法已被广泛应用于程序设计语言、形式定义、设计方法学、操作系统、分布式系统、人工智能、实时系统、数据库、人机接口、计算机体系结构以及并发工程、综合集成工程等,在许多领域的应用都得到了很大的发展。1986年在美国举行了首届\面向对象编程、系统、语言和应用(OOPSLA’86)\国际会议,使面向对象受到世人瞩目,其后每年都举行一次,这进一步标志OO方法的研究已普及到全世界。

二、面向对象的基本概念与特征

用计算机解决问题需要用程序设计语言对问题求解加以描述(即编程),实质上,软件是问题求解的一种表述形式。显然,假如软件能直接表现人求解问题的思维路径(即求解问题的方法),那么软件不仅容易被人理解,而且易于维护和修改,从而会保证软件的可靠性和可维护性,并能提高公共问题域中的软件模块和模块重用的可靠性。面向对象的机能念和

第 49 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

上学吧(www.shangxueba.com)

机制恰好可以使得按照人们通常的思维方式来建立问题域的模型,设计出尽可能自然地表现

求解方法的软件。

面向对象的基本概念

对象:对象是要研究的任何事物。从一本书到一家图书馆,单的整数到整数列庞大的数据库、极其复杂的自动化工厂、航天飞机都可看作对象,它不仅能表示有形的实体,也能表示无形的(抽象的)规则、计划或事件。对象由数据(描述事物的属性)和作用于数据的操作(体现事物的行为)构成一独立整体。从程序设计者来看,对象是一个程序模块,从用户来看,对象为他们提供所希望的行为。在对内的操作通常称为方法。

类:类是对象的模板。即类是对一组有相同数据和相同操作的对象的定义,一个类所包含的方法和数据描述一组对象的共同属性和行为。类是在对象之上的抽象,对象则是类的具体化,是类的实例。类可有其子类,也可有其它类,形成类层次结构。

消息:消息是对象之间进行通信的一种规格说明。一般它由三部分组成:接收消息的对象、消息名及实际变元。 面向对象主要特征:

封装性:封装是一种信息隐蔽技术,它体现于类的说明,是对象的重要特性。封装使数据和加工该数据的方法(函数)封装为一个整体,以实现独立性很强的模块,使得用户只能见到对象的外特性(对象能接受哪些消息,具有那些处理能力),而对象的内特性(保存内部状态的私有数据和实现加工能力的算法)对用户是隐蔽的。封装的目的在于把对象的设计者和对象者的使用分开,使用者不必知晓行为实现的细节,只须用设计者提供的消息来访问该对象。

继承性:继承性是子类自动共享父类之间数据和方法的机制。它由类的派生功能体现。一个类直接继职其它类的全部描述,同时可修改和扩充。

继职具有传达室递性。继职分为单继承(一个子类只有一父类)和多重继承(一个类有多个父类)。类的对象是各自封闭的,如果没继承性机制,则类对象中数据、方法就会出现大量重复。继承不仅支持系统的可重用性,而且还促进系统的可扩充性。 多态性:对象根据所接收的消息而做出动作。同一消息为不同的对象接受时可产生完全不同的行动,这种现象称为多态性。利用多态性用户可发送一个通用的信息,而将所有的实现细节都留给接受消息的对象自行决定,如是,同一消息即可调用不同的方法。例如:Print消息被发送给一图或表时调用的打印方法与将同样的Print消息发送给一正文文件而调用的打印方法会完全不同。多态性的实现受到继承性的支持,利用类继承的层次关系,把具有通用功能的协议存放在类层次中尽可能高的地方,而将实现这一功能的不同方法置于较低层次,这样,在这些低层次上生成的对象就能给通用消息以不同的响应。在OOPL中可通过在派生类中重定义基类函数(定义为重载函数或虚函数)来实现多态性。

综上可知,在OO方法中,对象和传递消息分别表现事物及事物间相互联系的概念。类和继承是是适应人们一般思维方式的描述范式。方法是允许作用于该类对象上的各种操作。这种对象、类、消息和方法的程序设计范式的基本点在于对象的封装性和类的继承性。通过封装能将对象的定义和对象的实现分开,通过继承能体现类与类之间的关系,以及由此带来的动态联编和实体的多态性,从而构成了面向对象的基本特征。

三、面向对象的新方法论、新范型、新技术

OO方法的作用和意义决不只局限于编程技术,它是一种新的程序设计范型--面向对象程序设计范型;是信息系统开发的新方法论--面向对象方法学;是正在兴起的新技术--面向对象技术。

面向对象程序设计范型:程序设计范型(以下简称程设范型)具体指的是程序设计的体裁,正如文学上有小说、诗歌、散文等体裁,程序设计体裁是用程序设计语言表达各种概念和各种结构的一套设施。

目前,程设范型分为:过程式程设范型、函数式程设范型,此外还有进程式程设范型、事件程设范型和类型系统程设范型。每一程设范型都有多种程序设计语言支持(如:

第 50 页,共 64页

上学吧为您提供“软件设计师”资料下载:http://www.shangxueba.com/share/e15.html

本文来源:https://www.bwwdw.com/article/kcfp.html

Top