一、面向对象方法学概述
传统的生命周期方法学在消除软件非结构化、促进软件开发工程化方面起了积极的作用,但仍有许多不足,存在的主要问题有:①生产率提高的幅度不能满足需要; ②软件重用程度很低; ③软件很难维护; ④软件往往不能真正满足用户需要。
传统方法:系统是过程的集合 、过程与数据实体交互、 过程接受输入产生输出、数据与处理分离。
面向对象方法:系统是对象的集合 、对象与其它对象交互、 对象发送与响应消息、数据与处理方法封装到对象。
面向对象的软件工程的全面运用:①面向对象分析OOA 、②面向对象设计OOD、③面向对象编程OOP、④面向对象测试OOT、⑤面向对象软件维护OOSM
之前讲过的喷泉模型就是以对象为驱动:生存期各阶段开发出来的“部件”都是类,各阶段对各个类的信息进行细化,面向对象方法改进了生存期各个阶段间的界面。
1、面向对象方法学的原则
①尽可能模拟人类习惯的思维方式,使开发软件的方法与过程尽可能地接近人类认识世界解决问题的方法与过程;
②使描述问题的问题空间/问题域与实现解法的解空间/求解域在结构上尽可能一致。
2、面向对象方法学的要点
①客观世界是由对象组成,任何事物都是对象,复杂对象可以由简单对象组成。
②所有对象都划分成各种对象类(简称类),每个类都定义了一组数据和一组方法。
③按照子类与父类的关系,将若干类组成一个层次结构的系统。
④对象彼此间仅能通过传递消息互相联系。
3、面向对象方法学的优点
①与人类习惯的思维方法一致
②稳定性好
③可重用性好
④可维护性好
⑤ 易开发大型软件产品
二、面向对象的基本概念
面向对象 = 对象 + 分类+ 继承+ 消息通信
面向对象方法是一种运用对象、类、继承、消息传递、多态性等概念构造系统的软件开发方法。
面向对象程序的每一个成份是对象,程序是通过新对象的建立和对象之间的通信执行的。
1、对象
面向对象开发模式的基本成份,是系统中描述客观事物的一个实体。 是构成系统的一个基本单位,由一组属性和一组对属性进行操作的服务组成。
对象 = 对象名+ 属性(数据)+ 操作(服务/方法)
属性是对自身性质的抽象,通过执行操作来改变
操作是描述对象执行的功能,通过消息传递为其他对象使用
特点
①以数据为中心:操作围绕对数据所需的处理来设置
②对象是主动的:对象是进行处理的主体
③实现了数据封装:私有数据对外隐藏、不可见
④本质上具有并行性:不同对象独立地处理自身的数据
⑤模块独立性好:对象内部各元素彼此结合紧密,内聚性强
2、类
具有相同特征(属性)和行为(操作)的对象的集合构成了类。
类的定义包括一组数据属性和一组合法操作。
类的定义可以视为一个具有类似特性与共同行为的对象的模板,可以用来产生对象。
在一个类中,每个对象都是类的实例,对象的状态包含在实例的属性中。
3、消息
消息是一个对象与另一个对象之间传递的信息,要求某个对象执行类中定义的某个操作。
消息的使用类似于函数调用,消息中指定了某一个对象名、一个操作名和一个参数表。
接收消息的对象执行消息中指定的操作,并将传递过来的实参与参数表中对应的形参结合起来。
4、继承
类与类之间可能具有一般化和特殊化关系,这种关系下形成的一种层次关联,即继承。
继承是父类和子类之间共享数据和方法的机制,子类自动地共享父类中定义的数据和方法。
5、多态
对象互相通信从而执行系统的功能,不同的对象对同一消息有不同的实现。
多态的实现受继承的支持: ①利用类继承的层次关系,把具有通用功能的消息存放在高层; ②实现该功能的不同的行为放在低层,在低层上生成的对象能够给通用消息以不同的响应。
6、面向对象的特点
①抽象性:对象的数据抽象和行为抽象;
②封装性:软件开发的重要原则,有两个含义;
③共享性: 同一类中所有实例共享数据结构和行为特征; 同一应用中所有实例通过继承实现共享; 不同应用中所有实例通过复用实现共享。
三、面向对象建模技术OMT
模型是为了理解事物而对事物做出的一种抽象,是对事物的一种无歧义的书面描述。
建模的目的是为了减少复杂性,系统分析员应从不同角度抽象出目标系统的特性,使用精确的表示方法构造系统的模型。
面向对象方法最基本的原则,是按照人们习惯的思维方式,用面向对象观点建立问题域的模型,开发出尽可能自然地表现求解方法的软件。
模型化过程是一个迭代过程,通过不断细化、完善,直至满足真正需求,为开发工作奠定基础。
面向对象方法开发软件,通常需要建立以下三种形式的模型:
1、对象模型
也叫静态模型,是OMT方法中最重要的部分,动态模型和功能模型依此而建立。
对象模型描述系统的静态结构,包括构成系统的对象类,它们的属性、操作及它们之间的关系。 通常,使用类图建立对象模型。
类图是对象模型的图形表示
类与类之间的关系叫关联,代表一组存在于两个或多个对象类之间、具有相同结构和含义的具体连接。关联可以是物理的,也可以是逻辑的。关联有普通关联、限定关联、聚合关联、泛化关联。
普通关联如
限定关联的限定提高了语义精确性,增强了查询能力,通常用在一对多或多对多的关联关系中,可以简化模型中的重数。 在类图中,限定词放在关联关系末端的一个小方框内。如
为了说明关联的性质,可能需要一些附加信息,可以引入一个关联类来记录这些信息。 在类图中,关联类通过一条虚线与关联连接。
连接属性:用附加的属性说明类间的联系
聚合关联
共享聚合(弱)
组合聚合(强)
泛化关联如
2、动态模型
要想对系统了解得比较清楚,应考察在任何时刻对象及其联系的改变。
着重描述系统与时间相关的动态行为,即系统的控制逻辑。涉及时序和改变的状况用动态模型来描述。
包括两个图:状态图和时序图。
状态图是一个状态和事件的网络,侧重描述每一类对象的动态行为:①状态:对某一时刻属性特征的概括;② 状态迁移:这一类对象在何时、对发生的哪些事件,做出何种响应。
时序图是一种交互图,描述对象之间的动态合作关系以及合作过程中的行为次序;展现了完成某项行为的一组对象和对象间传递的消息的时间顺序。
按时间顺序对控制流建模,注重消息的顺序,揭示了一个特定“场景”中对象的交互。场景也将“脚本”,是完成系统某个功能的一个事件序列。如移动电话系统的时序图
激活:生命线上的长方框,对象接收消息开始活动,表明某时间点哪个对象在执行。
3、功能模型
表示系统的功能性质,指明系统应该“做什么”,因此更直接地反映用户对目标系统的需求。
由多个数据流图组成,说明从外部输入,通过内部操作和存储,直到外部输出,整个的数据流情况。
用例模型描述系统的静态使用情况,它定义了系统的功能,回答“系统应该为每类用户做什么”。 描述从系统的外部执行者观看到的系统功能,而非系统内部功能的具体实现。展现了一组用例、行为者/角色及它们之间的关系。用用例图建立起来的系统模型,成为用例模型。需要识别角色(使用用例并与系统交互的任何人或物都是行为者,确定行为者对确定用例非常有用)和识别用例(从用户角度观察到的系统功能,即角色如何使用系统)。
用例之间的关系:①扩展(extend):通过向被扩展的用例添加动作来扩展用例。 被扩展的用例是一般用例,扩展的用例是特殊用例。②使用(use):由一个用例使用另一个用例。
用例建模
建模过程为:①定义系统; 找出系统边界以外的行为者/角色;
②描绘用例,定义用例间的关系;
③绘制用例图,编写用例描述,确认模型。
四、面向对象分析
OOA(Object-Oriented Analysis)的目的是理解应用问题和用户需求,准确定义问题域,建立问题域的精确模型。
OOA从分析陈述用户需求的文件开始,是抽取和整理用户需求,并建立问题域精确模型的过程,使用户需求逐步精确化、一致化、完全化。
分析工作主要包含理解、表达和验证。
1、基本过程
①问题域分析
②发现和定义对象与类
③识别对象的外部联系
④建立系统的静态结构模型
⑤建立系统的动态结构模型
2、五个层次
面向对象分析建立的系统模型以概念为中心,称为概念模型,由一组相关的类组成。
构造和评审OOA概念模型的活动由五个层次组成,即类与对象、结构、属性、服务和主题层。
(1)标识类与对象
类和对象是对与应用有关的概念的抽象,是说明应用问题的重要手段,是构成软件系统的基本元素。
面向对象分析的第一个层次,这一层工作是整个分析模型的基础。
类和对象的识别开始于搜索选定的问题陈述,标识可以表示问题领域概念的术语。
(2)标识属性和实例连接
对象所保存的信息称为它的属性。
属性层是对前面已识别的类和对象做进一步的说明。
类的属性描述的是状态信息。
每个对象的属性值表达该对象的状态值。
(3)标识服务和消息连接
对象收到消息后所能执行的操作,称为对象可提供的服务。
服务层的目的:定义对象的行为和对象间的通信(消息连接),说明各种对象是如何共同协作以使系统运作起来的。
(4)标识结构
结构层用于标记对象间的继承和组装关系,是处理OOA模型复杂性的机制之一。 典型的结构有两种:①一般化-特殊化结构(Gen-Spec) ②整体-部分结构(Whole-Part)
(5)识别主题
主题是把一组具有较强联系的类组织在一起而得到的类的集合,用来建立系统的高层抽象视图,表示OOA模型的整体框架。
通过划分主题,将复杂的对象模型分解成几个不同的范畴,有助于开发人员或用户理解一个大而复杂的系统模型,有助于组织一个大项目的工作。
主题的划分有一定的灵活性和随意性。
在概念上可以认为,OOA大体按照下列顺序进行:寻找类与对象,识别结构,识别主题,定义属性,建立动态模型,建立功能模型,定义服务。
五、面向对象设计
OOD是用面向对象观点建立求解域模型的过程,使软件工程师能够从实现的角度,确定从类中导出的对象,以及对象的相互关联,描述了:①对象间的关系如何达到; ②行为如何实现; ③对象间通信如何实现。
1、过程
将已建立的OOA模型变成OOD模型,运用面向对象技术进行软件设计,建立求解域模型,并补充一些与实现有关的部分。
逐渐扩充模型的过程,分两个阶段: 系统设计(高层设计) 和 对象设计(低层设计)
系统设计
即高层设计,开发系统的体系结构,构造应用软件的总体模型。
高层设计阶段标识在计算机环境中解决问题所需要的概念,并增加一批需要的类,包括可使应用软件与外部世界交互的类。
此阶段的输出是适合应用软件要求的类、类间的关系、应用的子系统视图规格说明。
对象设计
着重于对象及其相互交互的描述,是集中于类的详细设计,细化属性和方法。
在对象设计期间:创建属性的数据结构和操作过程的详细规约;定义属性的可见性,精化对象接口以定义完整的消息模型的细节。
2、准则
优秀的设计是权衡了各种因素,使系统在其整个生命周期中的总开销最小的设计。
①模块化:对象就是模块,把数据结构和操作方法结合在一起
②抽象:支持过程抽象和数据抽象(类)
③信息隐蔽:通过对象的封装性实现
④弱耦合 强内聚
⑤可重用:尽量使用已有的类,创建新类时应考虑将来的重用性
两种OOD的耦合
①交互耦合:对象间的耦合通过消息连接实现,应尽可能松散、尽量降低消息连接的复杂程度、 减少对象发送或接收的消息数
②继承耦合:应提高继承耦合程度,使特殊类尽量多继承一般类
三种OOD的内聚
①服务内聚:一个服务应该完成一个且仅完成一个功能
②类内聚:一个类只有一个用途,它的属性和服务是高内聚的
③一般-特殊内聚:设计出的一般-特殊结构,应该符合多数人的概念,应该是对相应的领域知识的正确抽取。
3、启发规则
帮助软件开发人员提高面向对象设计的质量。包括:
①设计结果应该清晰易懂
②一般-特殊结构的深度应适当
③设计简单的类
④使用简单的协议
⑤使用简单的服务
⑥把设计变动减至最小
4、系统分解
大多数系统的面向对象设计模型在逻辑上分为四大部分,对应于目标系统的四个垂直切片:
两种子系统间的交互方式:
① 客户—供应商关系:作为“客户”的子系统调用作为“供应商”的子系统,后者完成某些服务并返回结果。
②平等伙伴关系:每个子系统都可能调用其他子系统,每个子系统都必须了解其他子系统的接口。
5、设计类中的服务
OOA得出的对象模型,通常并不详细描述类中的服务;OOD是扩充、完善和细化OOA模型的过程,设计类中的服务是它的一项重要工作内容。
(1)确定类中应有的服务
综合考虑对象模型、动态模型和功能模型,将动态模型中对象的行为以及功能模型中的数据处理,转换成由适当的类所提供的服务。
状态图描绘了对象的生命周期,状态转换是执行对象服务的结果。事件表现为消息,接收消息的对象必然有消息选择符指定的服务。
功能模型指明了系统必须提供的服务,数据流图中的处理与对象提供的服务相对应。
(2)设计实现服务的方法
设计实现服务的算法:①算法复杂度,通常选用复杂度较低(即效率较高)的算法,但也不要过分追求高效率,应以能满足用户需求为准。②容易理解和容易实现,往往与高效率矛盾,应该对这两个因素适当折中。③易修改,尽可能预测将来可能做的修改,在设计时预先做准备。
选择数据结构:在分析阶段,仅需考虑系统中需要的信息的逻辑结构;在设计过程中,则需要选择能够方便、有效地实现算法的物理数据结构。
定义内部类和内部操作:在设计过程中,可能需要增添一些在需求陈述中没有提到的类,这些新增加的类,主要用来存放在执行算法过程中所得出的某些中间结果。
六、面向对象实现
面向对象实现包括两项工作: 把面向对象设计结果,翻译成用某种程序设计语言书写的面向对象程序;以及 测试并调试面向对象程序。
程序的质量基本上由面向对象设计的质量决定。
测试目标:用尽可能低的测试成本和尽可能少的测试方案发现尽可能多的错误。
1、程序设计语言
(1)面向对象语言的优点:一致的表示、可重用性、可维护性
(2)面向对象语言的技术特点:支持类与对象概念的机制 、实现整体-部分结构的机制 、实现一般-特殊结构的机制、 实现属性和服务的机制、 类型检查、 类库、 效率 、持久保存对象 、参数化类 、开发环境
(3)选择面向对象的语言:将来能否占主导地位 、可重用性、 类库和开发环境 、其它因素
2、程序设计风格
(1)提高可重用性:提高方法的内聚 、减少方法的规模、 保持方法的一致性、 把策略与实现分开 、全面覆盖 、尽量不使用全局信息 、利用继承机制
(2)提高可扩充性: 封装实现策略、 不要用一个方法遍历多条关联链 、避免使用多分支语句、 精心确定公有方法
(3)提高健壮性: 预防用户的操作错误、 检查参数的合法性 、不要预先确定限制条件、 先测试后优化
3、测试策略
从小规模测试开始,逐步过渡到大规模测试,就是从单元测试开始,逐步进入集成测试,最后进行确认测试和系统测试。
(1)面向对象的单元测试: 类和类的实例包装了属性和处理这些数据的操作; 最小的可测试单元是封装起来的类和对象。
(2)面向对象的集成测试
基于线程的测试:把响应系统的一个输入或一个事件所需要的一组了集成起来。分别集成并测试每个线程,同时应用回归测试以保证没有产生副作用。
基于使用的测试:首先测试几乎不使用服务器类的那些类(称为独立类),测试完独立类后,接下来测试使用独立类的下一个层次的类(称为依赖类)。对依赖类的测试一个层次一个层次继续下去,直到整个系统构造完为止。
(3)面向对象的确认测试: 黑盒测试可以用来设计确认测试用例; 对于面向对象的软件来说,主要还是根据动态模型和描述系统行为的脚本来设计确认测试用例。
4、设计测试用例
目前,面向对象的软件测试用例的设计方法,还处于研究、发展阶段。与传统软件测试不同,面向对象测试关注于设计适当的操作序列以检查类的状态。
(1)测试类的方法
单元测试主要测试单个类和类中封装的方法。
测试单个类的方法主要有:随机测试、划分测试和基于故障的测试。
(2)集成测试方法
对类间协作进行测试。
可以使用随机测试方法和划分测试方法,以及基于情景的测试和行为测试来完成。