面向对象实现.ppt
第12章 面向对象的实现,第12章 面向对象实现,12.1 程序设计语言12.2 程序设计风格12.3 测试策略12.4 设计测试用例12.5 小结,2,面向对象实现与面向过程的一样应包括:编码,测试。面向对象的分析和设计共同的模型使它们难于分开。面向对象编程(OOP)需要OOP语言OOLOOL具有自己的特点和风格。面向对象程序中的封装、继承和多态等机制,给测试带来新特点,增加了测试和调试的难度。,3,面向对象的设计适宜用OOL来实现,理论上也可以用非OOL实现但不可取。若用非OOL编写面向对象程序,则程序员必须自己实现OOL编译程序自动提供的面向对象的概念和机制:类,继承,封装。,12.1 程序设计语言 12.1.1 面向对象语言OOL的优点,4,1.一致的表示方法面向对象开发基于不随时间变化的、一致的表示方法OO模型:OOA,OOD,OOP。2.可重用性软件开发组织可重用OOA,OOD和OOP结果。3.可维护性保持文档与源程序完全一致几乎不可能。OOL的可读性(对象名等)=可维护性。,5,1.支持类与对象概念的机制:内存管理 允许用户动态创建对象意味着系统必须处理内存管理问题。有两种管理内存的方法:1)语言的运行机制自动管理内存,即自动回收“垃圾”的机制;(必须采用先进的垃圾收集算法)2)由程序员编写释放内存的代码。(例如:程序员定义析构函数(destructor)。每当一个对象超出范围或被显式删除时,就自动调用析构函数。这种机制使得程序员能够方便地构造和唤醒释放内存的操作),6,12.1.2 面向对象语言的技术特点,2.实现整体-部分(即聚集)结构的机制两种实现关联方法:指针和独立的关联对象 大多数现有的面向对象语言并不显式支持独立的关联对象,在这种情况下,使用指针是最容易的实现关联的方法。,7,3.实现一般-特殊(即泛化)结构的机制实现继承+解决名字冲突。名字冲突指的是继承多个基类可能出现的重名问题。某些语言拒绝接受有名字冲突的程序,另一些语言提供了解决冲突的协议。程序员应该尽力避免出现名字冲突。,8,4.实现属性和服务的机制属性的机制:支持实例连接;属性的可见性控制;对属性值的约束。服务的机制:支持消息连接(即表达对象交互关系);控制服务可见性;动态联编。,9,5.类型检查强/弱类型:语法规定变量/属性分类的严格性。强类型优点:一是在编译时能发现程序错误,二是增加了优化的可能性。强类型有助于提高软件的可靠性和运行效率.强类型宜用于开发软件产品,弱类型适于快速开发原型。,10,6.类库类库:编译/开发环境提供的重用类构件。类库包含实现通用数据结构(例如,动态数组、表、队列、栈、树等等)的类,GUI用户界面类。7.效率面向对象语言的主要缺点是效率低:解释型语言,动态联编.类库中提供的算法和数据结构更高效.差别可以忽略,利大于弊。,11,8.持久保存对象不依赖于程序执行的生命期而长时间保存数据对象的两个原因:(1)实现在不同时运行程序间传递数据(2)恢复被中断了的程序的运行理想情况下,应该使程序设计语言语法与对象存储管理语法实现无缝集成。,12,9.参数化类类的数据(属性)类型可以由参数给定。一个类可以对不同的数据类型施以同样的操作。如对整数和实数排序。Eiffel 和C+语言提供了参数化类/类模板。10.开发环境软件工具或开发环境对软件生产率有很大影响。一个语言可有不同的编译程序。CASE工具与语言的兼容性。,13,选择面向对象语言应考虑的因素:1.将来能否占主导地位语言的生命力及稳定性:维护的考虑。2.可重用性影响重用的要素:封装,继承,多态。3.类库和开发环境语言、开发环境和类库这3个因素共同决定可重用性。类库是否提供有价值的类?开发环境是否提供使用方便的类库编辑和浏览工具。,12.1.3 选择面向对象语言,14,4.其他因素 在选择编程语言时,应该考虑的其他因素还有:对用户学习面向对象分析、设计和编码技术所能提供的培训服务;在使用这个面向对象语言期间能提供的技术支持;能提供给开发人员使用的开发工具、开发平台、发行平台;对机器性能和内存的需求;集成已有软件的容易程度(调用其它语言的模块)。,15,为适应面向对象方法所特有的概念(例如,继承性)而必须遵循的一些新准则。,12.2 程序设计风格,16,两种代码重用:1)本项目内的代码重用,2)重用旧/外项目的代码。1)内部重用:利用继承机制共享相同或相似的部分,12.2.1 提高可重用性,16,两种代码重用:1)本项目内的代码重用,2)重用旧/外项目的代码。1)内部重用:利用继承机制共享相同或相似的部分,12.2.1 提高可重用性,17,实现两类重用的程序设计准则:1.提高方法的内聚一个方法(即服务)只完成单个功能,否则把它分解成几个更小的方法。2.减小方法的规模把规模过大的方法(代码长度超过一页纸),分解成几个更小的方法。3.保持方法的一致性功能相似的方法应该有一致的名字、参数特征(包括参数个数、类型和次序)、返回值类型、使用条件及出错条件等。,18,4.把策略与实现分开两种不同类型的方法:策略与实现。策略方法(拼积木)调用实现方法(积木)来完成任务(实现图案)。策略方法通常紧密依赖于具体应用。实现方法针对具体数据完成特定处理,用于实现复杂的算法。相对独立于应用,因此,较可能被重用。,19,5.全面覆盖方法的实现不仅满足当前应用而且应该考虑其它应用的潜在需要。此外,方法对空值、极限值及界外值等异常情况也应该能够作出有意义的响应。6.尽量不使用全局信息应该尽量降低方法与外界的耦合程度,不使用全局信息,如类变量。,20,7.利用继承机制继承是实现共享和提高重用的主要途径。(1)调用子过程:把公共的代码分离出来,构成一个被其他方法调用的公用方法,并在基类中定义它。(2)分解因子。从不同类的相似方法中分解出不同的“因子”(即不同的代码),把余下的代码作为公用方法中的公共代码,把分解出的因子作为名字相同(多态性机制)算法不同的方法,放在不同类中定义,并被这个公用方法调用,如图所示。,21,(3)使用委托。仅当确实存在一般-特殊关系时,使用继承才是恰当的,否则,可以利用委托机制。(4)把代码封装在类中。(与继承无关)把被重用的代码封装在类中比较安全和修改。,22,提高可重用性的准则,也能提高程序的可扩充性。此外,下列准则也有助于提高可扩充性:1.封装实现策略把类的实现策略(包括描述属性的数据结构、修改属性的算法等)封装起来,将提高今后修改数据结构或算法的自由度。,12.2.2 提高可扩充性,23,2.不要用一个方法遍历多条关联链一个方法应该只包含对象模型中的有限内容,除非内容与方法无关。否则将导致方法过分复杂,既不易理解,也不易修改扩充。3.避免使用多分支语句可以利用DO_CASE语句测试对象的内部状态,而不要用来根据对象类型选择应有的行为(强耦合),否则在增添新类时将不得不修改原有的代码。应该利用多态性机制,根据对象当前类型,自动决定应有的行为。,24,4.精心确定公有方法公有方法是向公众公布的接口。对这类方法的修改往往会涉及许多其他类。为提高稳定性,可修改性,降低维护成本,必须精心选择和定义公有方法。删除、增加或修改私有方法所涉及的面要窄得多,因此代价也比较低。,25,既应该考虑效率,也应该考虑健壮性。需要在健壮性与效率之间做出适当的折衷。为提高健壮性应该遵守以下几条准则:1.预防用户的操作错误 软件系统必须具有处理用户操作错误的能力。任何一个接收用户输入数据的方法,对其接收到的数据都必须进行检查,发现了错误,应该给出恰当的提示信息,并准备再次接收用户的输入。,12.2.3 提高健壮性,26,2.检查参数的合法性 对公有方法,尤其应该着重检查其参数的合法性,因为调用公有方法时可能违反参数的约束条件。3.不要轻易限定数据容量 在设计阶段,很难准确地预测出应用系统中数据结构的最大容量需求。如果有必要和可能,应该使用动态内存分配机制。,27,4.先测试后优化 测试程序的性能以确定是否为提高效率而进行优化。如果实现某个操作的算法有许多种,则应该综合考虑内存需求、速度及实现的简易程度等因素,经合理折衷选定适当的算法。,28,测试面向对象软件的策略与与面向过程的策略基本相同,但也有许多新特点。,12.3 测试策略,29,最小的可测试单元是单个封装起来的类和对象。测试一个类就是测试它的对象子集(不可穷尽).测试对象主要是测试它的操作.不能孤立地测试单个操作:同一个操作在不同状态下行为不同.同一个操作在不同类中有不同的实现(多态性).有必要在每个子类的语境中测试操作比面向过程更复杂,12.3.1 面向对象的单元测试,30,集成=组装有关联的类不存在层次的控制结构(隐含在类中)传统的自顶向下/自底向上的集成策略无意义。,12.3.2 面向对象的集成测试,31,面向对象软件的集成测试的两种策略:(1)基于线程的测试(thread based testing):把响应系统的一个输入或一个事件所需要的那些类(线程)集成起来。(2)基于使用的测试(use based testing):首先测试独立类(几乎不使用其它类的类),再测试使用独立类的下一个层次的类(称为依赖类)。据此依赖关系持续下去,直至把整个软件系统构造完为止。集群测试(cluster testing):用精心设计的测试用例检查一群相互协作的类(通过研究对象模型可以确定协作类),以发现不同的类之间的协作错误。,32,和传统的确认测试一样,面向对象软件的确认测试也集中检查用户可见的动作和用户可识别的输出。从动态模型和描述系统行为的脚本可导出确认测试用例,以发现用户交互需求可能错误的情景。黑盒测试方法也可用于设计上述确认测试用例。,12.3.3 面向对象的确认测试,33,与传统软件测试不同,面向对象测试关注设计适当的操作序列以检查类的状态。(1)传统方法的可用性 白盒测试:用于类级别的测试。测试类中封装的操作,检查类的状态以确定是否存在错误。黑盒测试:用于集成测试、确认测试。,12.4 设计测试用例,34,着重测试单个类和类中封装的方法主要有:随机测试、划分测试和基于故障的测试等3种。,12.4.1 测试类(单元)的方法,34,1.随机测试随机选取测试类操作序列以测试该类对象不同的生命历史问题的性质隐含了一些限制例:银行应用系统的account(账户)类有下列操作:open(打开),setup(建立),deposit(存款),withdraw(取款),balance(余额),summarize(清单),creditLimit(透支限额)和close(关闭)。限制:必须在其他操作前打开账户,完成了全部操作之后才能(/必须)关闭账户。,35,一个account类实例的最小(正常)行为历史包含下列操作:opensetupdeposit.withdrawclose可能发生许多其他行为:Opensetupdeposit deposit|withdraw|balance|summarize|creditLimitn.withdrawclose从上列序列可以随机地产生一系列不同的操作序列:#r1:opensetupdepositdepositbalancesummarize.withdrawclose#r2:opensetupdepositcreditLimitwithdrawclose也要考虑异常(用户或编程)序列:opensetup.withdrawclosesetupdeposit.withdrawclose,36,2.划分测试划分测试(partition testing)可以减少测试用例的数量。3种划分:状态,属性,功能。(1)基于状态的划分根据类操作是否改变类状态来划分。考虑account类,状态操作包括deposit和withdraw,而非状态操作有balance,summarize和creditLimit。然后为每个类别设计测试序列。用例应覆盖各类操作的每一操作。,37,(2)基于属性的划分根据类操作使用的属性来划分。对于account类来说,可使用属性balance(余额=状态)把操作划分成3个类别:使用balance的操作;修改balance的操作;不使用也不修改balance的操作。用重要属性(状态)而非每个属性来划分。,38,(3)基于功能的划分根据类操作所完成的功能来划分。例如,可以把account类中的操作分类为初始化操作(open,setup),计算操作(deposit,withdraw),查询操作(balance,summarize,creditLimit)和终止操作(close)。,39,3.基于故障的测试 Fault based testing与传统的错误推测法类似,首先推测软件中可能有的错误,然后设计出最可能发现这些错误的测试用例。它的效率依靠测试人员的经验和直觉。它与面向对象的方法无关。,40,集成测试用例主要针对类间协作进行测试。测试类间协作可运用基于使用的测试策略,找出相互依赖的类.然后设计用例触发类间的各种交互序列.测试类协作可以使用随机测试方法和划分测试方法,以及基于情景/脚本的测试和行为测试来完成。UML的协作图能帮助我们找出相互依赖的类和交互序列.,12.4.2 集成测试方法,41,图12.3 银行系统的类-协作图,42,箭头线上的标注:协作而调用的操作,1.多类测试生成多个类的测试用例步骤:1)对每个客户/UI类,为其生成一系列测试序列来覆盖所有操作。2)对这些操作所生成的每个消息,确定接收消息的协作类/服务器对象中的对应操作。3)把每个2)的操作,结合进测试序列中。对每个产生消息的操作,继续2),43,例,储户存款,操作序列:ATM:cardInserted.password.depositBank:verifyAcctverifyPINdepositReqValidationInfo:validAcct validPINAccount:deposit#r4:verifyAcctBankvalidAcctValidationInfoverifyPINBankvalidPINvalidationInfodepositReqdepositaccount,44,多个类的划分测试方法类似于单个类。另一种划分测试方法,根据与特定类的接口来划分类操作。Bank类接收来自ATM类和Cashier类的消息,可以把Bank类中的方法划分成服务于ATM和Cashier的两类来测试它们。,45,2.从动态模型导出测试用例类的状态图可以帮助我们导出测试该类(及与其协作的那些类)的动态行为的测试用例。,46,设计出的测试用例至少应该覆盖所有状态:#s1:opensetupAccntdeposit(initial)withdraw(final)close导出更多测试用例,以保证所有行为都被测试:#s2:opensetupAccntdeposit(initial)depositbalancecreditwithdraw(final)close#s3:opensetupAccntdeposit(initial)depositwithdrawaccntInfowithdraw(final)close在多个类协作的情况下,应该使用多个状态图。,47,面向对象设计原则上不依赖于特定的实现环境,但实现结果和成本却取决于实现环境。支持面向对象设计范式的程序语言、开发环境及类库,对于面向对象的实现非常重要。具有方便的开发环境和丰富的类库的面向对象程序设计语言,是实现面向对象设计的最佳选择。良好的程序设计风格对于面向对象实现来说同样重要。传统的程序设计风格准则依然成立,面向对象方法还有一些新准则。,12.5 小结,48,面向对象测试的策略和技术与传统测试有所不同,对象类成为测试的焦点。测试类时使用的方法主要有随机测试、划分测试和基于故障的测试。每种方法都测试类中封装的操作。每种操作要在不同的对象状态(由对象的属性值表示)下测试。可以采用基于线程或基于使用的策略完成集成测试。从动态模型导出的测试用例,可以测试指定的类及其协作者。面向对象系统的确认测试可以用传统的黑盒方法完成。情景/脚本为系统确认测试提供了用例。,49,Test Tools,CASE tool index-Quite a comprehensive list of CASE Tools Old site:http:/www.cs.queensu.ca/Software-Engineering/toolcat.html400 categories;10%for testList of Test related tools,50,LOGISCOPE,LOGISCOPE:Software Quality,Testing,Maintenance and Reverse-Engineering http:/Rational Performance Tester 和 HP Mercury LoadRunner 的比较http:/,51,Mercury Interactivewww.M,With Mercury Quality Center,you can:Standardize and manage the entire quality process.Make quality decisions based on business risks and priorities.Reduce application deployment risk.Improve application quality and reliability.Manage application change impact through manual and automated functional testing.Track quality assets and progress across releases and test cycles.Warehouse critical application quality project data.Test service-oriented architecture services for both functionality and performance.Ensure support for all environments including J2EE,.NET,Oracle and SAP.,52,IBM Rational quality management,53,