面向对象分析与设计
课程介绍
软件系统开发的两个重要阶段:分析、设计
分析:发现正确的问题
设计:发现正确的解决方案
分析+设计=建模(modeling)
建模的结果就是模型。
软件开发有两种思维方式:面向过程和面向对象
面向过程(结构化方法)
- 典型如C语言、Pascal,侧重于如何分解和编写方法。
- 对问题领域的映射是间接的。
- 系统需要完成的功能,分配到各个函数。
- 每个函数代码量一般较小。
- 系统从主函数main()开始执行,通过不断的函数调用完成任务。
- 过程:需要自顶向下逐层的功能分解。
- 结果:一系列的 模块+接口。
- 优点:直接反映用户需求,上手快。
缺点:对于复杂领域问题,容易走错路,导致修改难,适应性差。
面向对象
- 典型如C++和Java,侧重于对象和类的辨识和设计。
- 面向对象的分析与设计(OOAD),蕴含一系列的概念和方法:
对象、类、继承、封装、聚合、关联、消息、多态、抽象...
- 对问题领域的映射是直接的和如实的:抽象出对象和类,并将数据和方法进行封装,利用继承、多态等技术进行设计...
- 从主函数开始执行,通过对象的相互协调调用完成任务。
UML:Unified Modeling Language
面向对象的基本概念
类、对象、封装、继承、多态
封装:受保护的类的属性和方法,不被外界访问
继承:定义子类时,保留父类方法和属性和方法
多态:在继承的版本上表现出不同的版本
类
包含三个区域:类名、属性、方法
对象时类的实例,类是对象的模板
继承
基本原理:子类继承父类的属性和方法。
- 子类还可以增加新的属性和方法。
- 子类还可以覆盖父类的属性和方法(overriding)。
- 在Java中,子类只能继承一个父类;在C++中则可以多重继承。
多态
基本原理:需要父类对象时,可以用子类对象替代。
- 消息发送方不需要知道消息接收方属于那个子类。
- 消息接收者可以按自己的方式处理消息。
- 也就是说,对于同一个消息,每个接受方按自己的方式处理。
聚合/组合
继承:子类继承父类。is a :a car is a vehicle
聚合:一个物体是另一个物体的一部分,has a。“A car has wheels”。聚合关系是传递的,非对称的。
组合:聚合关系的变型,是更强的聚合,整体控制着部分的生命,整体没有了,部分也没有了。“手与手指”。
接口/实现
- 对于软件系统:内部由大量的互相关联的类构成,当对其中某一个类进行修改的时候,不能影响其它的类。
- 接口描述一个类的用户如何与这个类交互。
- 实现:完成接口所定义的功能,如类、构件等完成的任务。
- 对于实现的改变,不影响接口,也就不影响使用了该接口的软件。
- 也就是说,接口/实现都要遵从“interface specification”。
Coad和Yourdon的观点
***** 面向对象 = 对象 + 分类 + 继承 + 消息通信
***** 面向对象的基本建模原则:抽象,封装,继承,分类
***** *对象:***客观现实世界中一个实际存在的事物
***** 类:****具有相同属性和行为的一组对象的集合(抽象性)
*** 封装:**把对象的属性和行为组成一个独立的系统单位,并尽可能隐蔽对象的内部细节
***** 继承:****特殊类的对象拥有其一般类的全部属性和行为
多态: 指在一般类中定义的属性或行为,被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为
消息通信:对象之间只能通过消息进行通信,所有相关对象之间相互协作完成软件功能
面向对象语言
Simula:面向对象语言的基本思想源于Simula
Smalltalk:公认的历史上第二个面向对象的程序设计语言和第一个真正的集成开发环境
软件生命周期
指一个软件从提出开发要求开始,到软件报废为止的整个时期。
生命周期的阶段:问题定义、可行性分析、需求分析、总体(概要)设计、详细设计、编码、测试、维护
面向对象的分析(OOA):根据系统要求,找出所有的对象,对象的属性及方法。根据对象的共性,定义类。
面向对象的设计(OOD):对象属性方法三者封装在一起。对象之间的协作考消息通信实现。
Coad & Yourdon方法
OOA和OOD采用完全一致的方法。
主要概念:对象,类,属性,服务,整体-部分结构,一般-特殊结构,实例连接,消息连接,主题
OOA模型包含5层:主题层,类和对象层,结构层,属性层,服务层
RDD方法
职责驱动法RDD,又称CRC(类-责任-协作)法。
核心: ①用类所承担的责任来描述系统;②用索引卡(即CRC卡)来捕获初始的类、责任和协作,同时也记录超类-子类关系以及由超类定义的公共职责
- 工作步骤:
(1)识别类和职责。 (2)分配职责。 (3)寻找协作。 (4)细化。
面向对象方法的优缺点
优点:
软件质量评价标准(13条):正确性、灵活性及可靠性(健壮性)、可维护性与可扩展性、可重用性及通用性、互操作性、效率、可移植性、可验证性、安全性、友善性、可描述性及可理解性。
对模块性的支持:- 5个标准,即可分解性、组合性、可理解性、连续性和保护性。
对软件开发过程的支持:软件工程的演化式开发方法具有能适应需求变化、灵活、可扩展、重用等优点,面向对象方法有力地支持了这样的开发模式,从而促进了大型软件系统的开发。
封装+继承+标识=可重用性+可扩展性+丰富的语义
面向对象的分析与设计的一般过程
1. 描述需求
2. 识别潜在对象
3. 筛选对象
4. 对象的命名
5. 识别对象的属性
6. 识别对象的行为
7. 识别对象所属的类
8. 定义类的结构
8.1 整体部分结构
8.2 一般特殊结构
8.3 实例连接
8.4 消息连接
9. 通过在类的操作中编写代码,完成一项功能
§10. 通过消息连接(即类之间的协作),完成一项功能
统一建模语言UML概述
模型
模型:为了理解事物而对事物做出的一种抽象,是对事物规范的、无歧义的描述;忽略了非本质的细节。
模型的分类:数学模型、描述模型、图形模型
建模的原则:准确、分层、分治、标准
UML的概念
UML:Unified Modeling Language(统一建模语言)的首字母缩写词
- 是一种建模语言,不是一种建模方法
- 用于建立分析和设计模型,不是用于编程
- 是一种已被OMG采纳的建模语言规范(specification),一般不称为standard, 部分采用形式化语言的定义方式,但并不严格。
- 故不是形式化语言,不能编译或解释执行。
UML的特点:统一的标准、面向对象、可视化、独立于过程、概念明确
UML的构成:3个要素:基本构造块、规则、公共机制
基本构造块:事物(结构、行为、分组、注释)、关系(依赖、关联、泛化、实现)、图(十种,其中,类图是核心,OOAD的目的,就是获取类图,也就确定了逻辑代码的框架,也能发现设计中的问题,优化代码)
规则:名字、作用域、可见性、完整性、执行
公共机制:规范说明、修饰、公共划分、扩展机制
事物、关系——模型元素
事物
- 结构事物
- UML模型中的名词,通常是模型的静态部分,描述概念元素或物理元素
- 总称为类目,包括类、接口、协作、用例、主动类、组件…。- 行为事物
- UML模型中的动词,通常是模型的动态部分,描述跨越时间/空间的行为。
- 包括交互、状态机和活动。
- 分组事物
- UML模型的组织部分,是一些由模型分解成的“盒子”。
- 主要的分组事物是包。整个模型可以看成是一个根包,它间接包含了模型中的所有内容。子系统是另一种特殊的包。
- 注释事物
- UML模型的解释部分,用来描述、说明和标注模型的任何元素。
- 主要的注释事物是注解,提供依附于元素之上的信息的文本说明
- 行为事物
关系
* 依赖关系是一种使用关系,说明一个事物使用另一个事物的信息和服务(一条实线)
* 关联关系是一种结构关系,说明一个事物的实例与另一个事物的实例间的静态联系(虚线+三角箭头)
* 泛化关系是一般事物(称为超类或父类)和该事物的较为特殊的种类(称为子类)之间的继承关系(虚线+指向符)
* 实现关系是事物之间的语义关系,说明一个事物提供了另一个事物的功能契约的实现(实线+三角箭头)
UML的视图
视图:
- 视图代表在一个特定的方面对系统的组织和结构进行的投影
- 视图又由一种或多种模型图构成
- 可以将所有UML图归属为4种建模技术
(1)需求建模:通过用例图描述需求。
(2)静态建模:通过类图和对象图描述软件系统的静态元素。
(3)动态建模。通过协作图、顺序图、活动图、状态图描述静态元素的行为。
(4)构架建模。通过组件图和部署图,在多个层次(如表示、业务、资源)上描述软件系统的构架。
- UML把软件体系结构划分为5个视图
- 每一个视图又由一种或多种模型图构成
- 所有视图结合在一起就描述了系统的完整画面。
- 5种视图:
- 用例视图:由用例图表现。需求分析,定义边界,关注系统功能
- 逻辑视图:静态部分由类图和对象图表现;动态部分由顺序图、协作图、状态图和活动图表现。逻辑视图定义系统的实现逻辑。
- 进程视图:由顺序图、协作图、状态图和活动图表现。描述给定时刻系统中不同的执行进程,说明系统中并发执行和同步的情况。焦点是通过性能、可伸缩性和吞吐量来评价进程的执行。
- 实现视图:由组件图表现。说明代码的结构,描述的是组成一个软件系统的各个物理部件,它们以各种方式组合起来,构成一个可实际运行的系统。
- 部署视图:由部署图表现。描述软件系统在计算机硬件系统和网络上的安装、分发和分布情况。
这五个视图一般称为:4+1视图,用例视图是4+1的核心
- 视图的参与人员
- 用例视图:使用者:最终用户、开发人员、测试人员
- 逻辑视图:使用者:分析人员、开发人员
- 进程视图:使用者:分析人员、开发人员、系统集成人员
- 实现视图:使用者:最终用户、开发人员、测试人员、项目管理者
- 部署视图:使用者:最终用户、开发人员、系统集成人员、测试人员
用例图
构成:边界、参与者、用例、关系
参与者
指系统以外的、需要使用系统或与系统交互的外部实体。
可分为:人、外部设备、外部系统
参与者是人:用“小人图”
参与者是某个系统:用方框图,构造《actor》
参与者之间的关系
* 泛化关系:一般参与者与特殊参与者之间的关系(特殊指向一般)
实线 + 空心箭头
参与者和用例之间的关系
1 | * 关联关系:起通信的作用,即描述了:一个参与者完成系统的一项功能。用实线表示。是一种拥有的关系,它使一个类知道另一个类的属性和方法;如:老师与学生,丈夫与妻子关联可以是双向的,也可以是单向的。双向的关联可以有两个箭头或者没有箭头,单向的关联有一个箭头。 |
用例之间的的关系
用例之间的关系:泛化关系,包含关系,扩展关系
包含关系:基本用例的行为必然执行包含用例的行为,用《include》
基用例必须和包含用例一起使用才够完整,包含用例也必然被执行。包含关系在用例图中使用带箭头的虚线表示(在线上标注<>),箭头从基用例指向包含用例。
扩展关系:基本用例的行为条件执行扩展用例的行为,用《extend》
扩展用例是对基用例的扩展,即使没有扩展用例的参与,也可以完成一个完整的功能。扩展在用例图中使用带箭头的虚线表示(在线上标注<>),箭头从扩展用例指向基用例。
类图和对象图
对象:一般意义上,是现实世界中一个实际存在的事物
- 对象可以是有形的(比如一辆汽车),也可以是无形的(比如一项计划)
- 对象是一个独立单位,具有自己的静态特征和动态特征。
静态特征是可以用某种数据来描述的属性
动态特征是对象所表现的行为或对象所具有的功能
类:具有相同属性和服务的一组对象的集合。
类图的表示
四个部分:分为三个隔区的长方形,包含名称、属性、操作、职责
类的可见性:
+(公有属性Public):能够被系统中其他任何操作查看和使用
-(私有属性Private):仅在类内部可见,只有类内部的操作才能存取该属性
#(受保护属性Protected):供类中的操作存取,也可被其子类使用
类的作用域
* 对象作用域指的是此类的每个对象都有一个自己的副本,彼此不共享属性值
* 类作用域指的是只有一个副本,类的所有对象共享此副本。即共享属性值
类之间的关系
关联关系:一个类的实例与另一个类的实例在结构上的静态联系
特征:
- 一个类的属性的数据类型是另一个类的定义
- 一个类的部分对象与另一个类的部分对象存在属性值上的联系
- 关联关系一旦建立,系统运行与否它都存在
* 关联类(Association Class):如果在具有关联关系的类中,存在一个属性放在哪个类中都不合适的情况,就可以使用关联类
*
- 用虚线表示关联类的关联关系
* 关联约束:对于关联可以加上一些约束,以加强关联的含义
限定关联:在关联端紧靠源类图标处可以有限定符。限定符的作用就是在给定关联一端的一个对象和限定符值以后,可确定另一端的一个对象或对象集
自反关联
一个类与自身关联,自返关联虽然只有一个被关联的类,但有两个关联端,每个关联端的角色不同。
自返关联虽然只有一个被关联的类,但有两个关联端,每个关联端的角色不同。
N元关联:3个或3个以上类之间的关联。
在同一时刻,每个类必须确定一个对象。
例:一个运动员(player)在某一个年份(year)中在某一个运动队(team)中服役。
聚合(聚集)关系:是一种特殊形式的关联,表示类之间整体与部分的关系。
整体与部分无相同的生存期。整体不存在了,部分仍能存在。
它用端点带有空菱形的线段表示, 空菱形与‘整体’类相连接
组成(组合)关系:是一种特殊形式的关联,表示类之间整体与部分的关系。
- 整体与部分有相同的生存期。整体不存在了,部分也不能存在。
- 用端点带有实菱形的线段表示,实菱形与‘整体’类相连接
依赖关系
* 定义:一个类的结构上的变化会影响到另一个类(代码级)
* 特征:
- 一个类的方法的参数的数据类型是另一个类的定义
- 一个类的方法使用了另一个类的属性
- 一个类的方法调用了另一个类的方法
- 一个类的方法实例化了另一个类的对象
- 一个类的每一个对象与另一个类的所有(或部分)对象存在操作运行上的联系
- 依赖关系只有在系统运行时它存在,系统不运行时它不存在
虚线+箭头
关联关系:
- 静态的
- 数据(指属性值)级别上的
- 部分的
- 有多重性
- 实体类之间存在关联关系
依赖关系:
- 动态的
- 代码级别上的
- 全体的
- 无多重性
- {边界类|控制类}和{边界类|控制类|实体类}之间存在依赖关系
泛化关系
- 定义:一般类与特殊类之间的继承(代码级)
- 特征:
- 一般类定义了共同的属性和方法
- 特殊类继承了一般类的属性和方法
- 特殊类还可以定义自己的属性和方法
- 泛化关系只有在系统运行时它存在,系统不运行时它不存在,除非要将两类对象永久保存
- 特征:
实线+空心箭头
抽象类与接口
抽象类
* 抽象类(abstract class):是不能直接产生实例的类。
* 抽象类可以有属性,但是必然存在某些方法只是一些声明,而没有具体的实现。其它的一些方法可以有实现。
* 抽象类一般作为超类(或基类、父类)存在,用于描述其他类的公共属性和操作。
接口
* 接口(interface):一个类的对外可见的一组操作的规范,它定义了类对外提供的服务。
* 接口包含操作但不包含属性。所有的操作只是一些声明,而没有具体的实现。
* 不能对接口实例化。
抽象类与接口的对比
* 共同点
- 两者都有方法没有提供实现代码
- 提供实现代码的其他类,实现的算法不同,会导致两者具有不同的行为。因此,很容易扩展软件系统的功能。
* 不同点
- 抽象类有些方法可以提供实现代码,接口所有的方法都没有提供实现代码
- 抽象类只能被继承,接口只能被实现
类的类型
UML中有3种主要的类版型
* 边界类(boundary class)
* 控制类(control class)
* 实体类(entity class)
引入边界类、控制类和实体类的概念,有助于分析人员和设计人员确定系统中的类
对象图
* 表示一组对象及它们之间的联系。
* 是系统的详细状态在某一时刻的快照,常用于表示复杂的类图的一个实例。
* 对象是类的实例,对象之间的链是类之间的关联的实例。因此,对象图实质上是具有关联关系的类图的实例
* 对象图所建立的对象模型描述的是某种特定的情况,而类图所建立的模型描述的是通用的情况。
类图 | 对象图 |
---|---|
在类图中,每个类包含三部分:类名、类的属性和类的操作 | 在对象图中,每个对象包含二部分:对象名、对象属性 |
类的名称栏只包含类名 | 对象的名称栏包含对象名和类名 |
类的属性栏定义了所有属性的特征 | 对象的属性栏定义了属性的当前值 |
类中列出了操作 | 对象图中的对象不包含操作,因为对于属于同一个类的对象,其操作是相同的 |
类中使用了关联连接,关联中使用关联名、角色以及约束等特征定义 | 对象使用链进行连接,链中包含名称、角色 |
类是对象的抽象 | 对象是客观存在的抽象,对象是类的实例 |
顺序图
* 描述对象之间按时间顺序进行的消息交互过程
* 顺序图可以用来描述一个用例的执行。消息的交互顺序可以和用例描述的流程进行相互印证
* 从而可以判断一个用例的行为是否已经分解到对象及其方法上了
* 顺序图是一个二维图形;
* 水平方向为对象维, 排列的是对象,对象的排列次序不重要, 但一般将主要的对象靠左,参与者排在两端。
* 垂直方向为时间维, 沿垂直向下方向按时间递增顺序列出各对象所发出的和接收的消息。
概念
对象:同类图中的对象,是类的实例。
生命线:从对象图标向下延申的一条虚线,表示对象存在的生命期。
消息:对象间的一次通信
分支:从一点发出的多条消息指向不同的对象,分为条件分支和并行分支。
从属流:从同一点发出多条消息,并指向同一对象的不同生命线。
2:display(x,y) | 简单消息(表示序号为2的消息,消息名为display,消息参数为x和y) |
---|---|
1.3.1:p:=find(specs) | *嵌套消息,消息带返回值(表示序号为1.3.1的嵌套消息,返回值名为p,消息名为find,消息参数为specs。* |
[x<0]4:invert(x,color) | 警戒条件消息(表示序号为4的消息,消息名为invert,消息参数为x和color。[x<0]是警戒条件。其含义是当条件x<0满足时,发送第4个消息invert) |
4.2[x>y]:invert(x,color) | 条件发送消息(表示序号为4.2的嵌套消息,消息名为 invert, 消息参数为 x 和 color 。[x>y]是消息顺序表达式中的条件发送格式。其含义是当条件x>y 满足时,发送第4.2个消息 invert。 |
3.1*:update() | 循环发送消息(表示序号为3. 1的消息,消息名为 update。无消息参数。*是消息顺序表达式中的循 环发送格式,其含义是循环发送第3. 1消息 update 多次。需要注意的是,循环*无论出现在消息序号的前面还是后面,都表示循环发送格式) |
---|---|
A3,B4/C2:copy(a,b) | 线程间同步(表示先发送线程A的第3个消息和线程B 的第4个消息后,才发送线程C的第2个消息,消息名为 copy,消息参数为a和 b。A3,B4为消息的前序,用来描述同步线程。C2 为消息顺序表达式中的消息顺序项,C表示并发的控制线程,2表示消 息序号****) |
1.1a,1.1b/1.2:continue() | 同时发送的并发消息作为先发消息序列(表示同时发送的并发消息1.la和1.1b之后,再发送序号为1.2的消息,消息名为 continue。1.la,1.1b为消息的前序,用来描述同步消息) |
消息的种类:
调用消息:调用(procedure call)消息的发送者把控制传递给消息的接收者,然后停止活动,等待消息接收者放弃或返回控制。调用消息可以用来表示同步的意义。也称同步消息
实线+实心箭头
异步消息:异步(asynchronous)消息的发送者通过消息把信号传递给消息的接收者,然后继续自己的活动,不等待接收者返回消息或控制。异步消息的接收者和发送者是并发工作的。
实线+指向箭头
返回消息:返回(return)消息表示前面发出的消息要返回的消息值。如果是从过程调用返回,则返回消息是隐含的,可以不用画出来。对于非过程调用,如果有返回消息,必须明确表示出来。如图所示虚线箭头表示对应于oper()这个消息的返回消息。
虚线+指向箭头
反身消息:消息的发送者和接收者是同一个对象
阻止消息:阻止消息是指消息发送者发出消息给接收者,如果接收者无法立即接收消息,则发送者放弃这个消息。
超时消息:超时消息是指消息发送者发出消息给接收者并按指定时间等待。如果接收者无法在指定时间内接收消息,则发送者放弃这个消息。
异步消息+圆圈
调用消息和异步消息的对比
调用消息主要用于控制流在完成之前需要中断的情况,异步消息主要用于控制流在完成之前不需要中断的情况。
- 在账号和密码的对错判断完成之前,对象“:Web页面”的第一个控制焦点表达的活动必须被中断。因此,“用户验证()”消息是调用消息。
- 在进行分数登记的时候,同时会写入日志文件,即分数登记操作不需要中断。也就是说,对象“:分数登记”的控制焦点表达的活动不会被中断。因此,“写入日志文件()”消息是异步消息。
协作图
协作图的概念
值得特别注意的是
* 在结构建模阶段,是可以得到下面这样的基于协作的类图。
* 在这种类图中,通过将虚线(类的依赖关系)换成实线(对象的连接关系),再附上消息,就可以得到协作图。
状态图和活动图
行为模型包括:状态模型、活动模型、交互模型
* 状态模型——使用状态图
* 活动模型——使用活动图
* 交互模型——使用顺序图、协作图
* 状态模型涉及一个对象,活动模型和交互模型涉及多个对象
转移的分叉:对于一个给定的状态,最终只能产生一个转移,因此从相同的状态出来的、时间相同的几个转移之间的条件应该是互斥的。
活动图:
* 描述系统行为的图,它把一项行为表示成一个可以由计算机、人或者其他执行者执行的活动,通过给出活动中的各个动作以及动作之间的转移关系来描述系统的行为。
* 特点:能描述并发行为,由多个对象协同完成功能,有参与者
* 是顶点和弧的集合
* 活动图的建模元素有:活动、分支、分叉和汇合、泳道和对象流等
活动图的分支:
* 一个分支可以有一个进入流和多个离去流
* 在每个离去流上必须设置一个监护条件
- 条件放在方括号里
- 条件不能重叠,以免二义性。可以有 [else] 分支
* 两个控制路径可以重新合并,无需监护条件
* 对于同一个触发事件,可以根据不同的警戒条件转向不同的活动,每个可能的转移是一个分支
活动图的分叉:
* 分叉表示的是一个控制流被两个或多个控制流代替,经过分叉后,这些控制流是并发进行的。
* 汇合正好与分叉相反,表示两个或多个控制流被一个控制流代替。
1 | 简述包含用例和扩展用例的性质,以及它们的相同点和不同点。 |