第七章 面向对象的分析
第一节 对象模型的建立
第二节 动态模型的建立
第三节 功能模型的
第四节 建立定义服务
面向对象分析的过程是提取系统需求并建立
精确模型的过程。在这个过程中,首先要 理解 问
题域,系统分析员通过与用户及领域专家的充分
交流,力求完全理解用户需求和该领域中关键性
的背景知识;然后用某种无二义性的方式将系统
分析员的理解 表达 成文档资料,建立起软件需求
规格说明书;由于问题的复杂性,而且人与人之
间的交流带有随意性和非形式化的特点,上述理
解和表达的过程通常不可能一次就达到理想的效
果,需要系统分析员与用户及领域专家多次反复
交流,对软件需求规格说明书进行 验证 。
理解、表达、验证三个过程交替进行,
反复迭代,而且往往需要利用原型系统作
为辅助工具。
第一节对象模型的建立
面向对象方法强调围绕对象而不是围绕
功能来构造系统。对象模型是对模拟客观
世界实体的对象及对象彼此间的关系的映
射,描述了系统的静态结构。用面向对象
方法开发软件,在任何情况下,对象模型
始终都是最重要、最基本、最核心的。
一、对象模型的结构
对象模型的结构由五个层次组成:
主题层、类 —&—对象层、结构层、属
性层和服务层。这五个层次很像叠在一起
的五张透明塑料片,它们一层比一层显现
出对象模型的更多细节。
主题层
( Subject layer)
类 —&—对象层
( Class & object layer)
结构层
( Structure layer)
属性层
( Attribute layer)
服务层
( Service layer)
主题
类边界
实例边界
属性
服务
实例连接
消息
对象模型的结构
(一 ) 类 —&—对象层
,类 —&—对象, 是一个专用术语,它
是指, 一个类及属于该类的实例(对
象), 。图( a)是表示类 —&—对象的图
形符号,实线的矩形框表示, 类,,用两
条横线分成三个部分,分别列出类的名字、
该类定义的属性以及该类提供的服务,类
符号外面加一个虚框表示属于该类的实例。
类 —&—对象表示符号
类名
属性
服务
类名
( a)
( b)
类名
属性
( c)
如果一个抽象类没有实例,虚框就不需
要。当不需要详细描述一个类内定义了那
些属性或服务时,有时将该符号简化成图
( b)或图( c)。
类 —&—对象层包含待开发系统的所有
类及对象,它是整个对象模型的基础。
(一 ) 结构层
结构层表示了问题域中实体间结构关系
的抽象。问题域中实体之间的结构关系可
以概括为两种:归纳关系、组合关系。图
(a)表示归纳关系,图 (b)表示组合关系。
( a) ( b)
一般类
特殊类 1 特殊类 2 部分 1 部分 2
x,y
x,y
x,y
x,y
整体
结构表示符号
1.归纳关系 归纳关系就是, 一般 ——特
殊, 关系, 它反映了一个类与若干个互不相容的
子类之间的分类关系 。 上图 ( a) 中上部是一个
一般类, 说明一般类及对象的特征 ( 属性和服
务 ), 下面是若干个特殊的类, 特殊类可以继承
一般类的特征, 在特殊类中只需说明特殊属性及
服务 。 一般类和特殊类之间用直线及半圆形标记
连接, 半圆形表示归纳关系的方向:从半圆形中
点引出的直线指到一般类 。 注意直线的端点在实
线框, 表明这是类之间的关系, 而不是对象之间
的关系 。 下图 ( a) 是归纳关系的一个例子 。
2.组合关系 组合关系就是, 整体 ——部分,
关系,它反映了对象之间的构成关系。上图( b)
中上部是一个整体对象,下部是组成该整体对象
的若干个部分对象,它们之间用直线及三角形标
记连接。注意直线端点的位臵在虚线框,表明这
是对象之间的关系。三角形标记表明组合关系的
方向:从三角形顶角引出的线指向整体对象,从
三角形底边中点画出的线连到部分对象。结构线
每端标出的数值有三种:, 1”(一个),,1+”
(多个),,x,y”( x个到 y个)。值为 1时通常
省略。下图( b)是组合关系的一个例子,表示
一架电脑由一个主机和多个外设组成。
员工 电脑
临时工 正式工
( a) ( b)
主机 外设
1+
归纳及组合关系的例子
(三 ) 主题层
大量事实表明, 一般情况下, 人们在一
个时间内的短期记忆限制在 7± 2个事件之内 。
对于大型系统, 由于对象模型的结构庞大而复
杂, 为了便于人们在一个时间内考虑和理解所
提出的对象, 可以将有关的类 —&—对象归类到
各个主题 。 主题可以看作对象模型的子模型或
子系统 。 主题用粗矩形框表示, 它把该主题中
所包含的所有类 —&—对象封闭起来, 在右下角
表明主题名 。
(四 ) 属性层
属性层包括两个方面,对象的属性 以及 对象
之间的关系 (实例连接)。对象的属性的含义已
经明白。现在来看一看什么是对象之间的关系。
现实世界中,实体之间存在着互相约束,上面所
述的组合关系就是实体之间的一种特殊的约束关
系,除了组合关系,还存在其它限制条件或事务
规则。例如,银行系统的一次取款事务必定跟某
个储户有关,没有储户,也就不存在取款事务。
对象模型的属性层中, 用实例连接映射这
种非组合关系的约束, 有三种实例连接方式:
1.一对一 ( 1,1) 例如一个国家拥有一个
政府, 一个政府唯一对应一个国家, 国家与政府
之间的实例连接是一对一 ( 见图 ( a), 数值 1通
常省略 ) 。
2.一对多 ( 1,1+) 例如一个教师可以拥
有多本书, 但一本书唯一对应一个教师, 教师与
书之间的实例连接是一对多 ( 见图 ( b)) 。
3.多对多( 1+,1+)例如一个作家可以写多
本书,一本书可以有多个作家合著编写,作家与
书之间的实例连接是多对多(见图( c))。
国家 政府 教师 书 作家 书
1+
1+ 1+
实例连接
( a) ( b) ( c)
(五 ) 服务层
服务层也包括两个方面:对象的服
务以及对象之间的消息通信。用两个对象
之间连接的有向箭头表示对象之间的消息
连接关系,从发送者指向接收者。
二, 对象模型的建立
对象模型的五个层次对应着建立对象模型的
五项活动:
? 识别类 —&—对象
? 识别结构
? 识别主题
? 定义属性和实例连接
? 定义服务和消息连接
必须强调指出的是,我们说的是, 五项活
动,,而没有说五个步骤,事实上,这五项活动
完全没有必要顺序完成,也无须彻底完成一项工
作以后再开始另外一项工作。
虽然这五项活动的抽象层次不同,但是我们
在进行面向对象分析时并不需要严格遵守自顶向
下的原则。
人们往往喜欢先在一个较高的抽象层次上工
作,如果在思考过程中突然想到一个具体事物,
就会把注意力转移到深入分析发掘这个具体领域,
然后又返回到原先所在的较高层次。
例如,分析员找出一个类 —&—对象,
想到在这个类中应该包含的一个服务,于
是把这个服务的名字写在服务层,然后又
返回到类 —&—对象层,继续寻找问题域中
的另一个类 —&—对象。
下面通过一个例子, 银行计算机储蓄系
统,, 简称, 储蓄系统, 。来描述如何进
行建立对象模型的五个活动。在建立对象
模型之前,分析员首先要同用户及问题领
域的专家进行交流,对问题域有个初步的
理解,用书面方式表达需求陈述。, 储蓄
系统, 需求陈述如下:
某银行总行下设几个分行,每个分行设
有下属的遍布市内各处的储蓄所。银行拟
开发一个, 银行计算机储蓄系统,,它是
一个由中央计算机、分行计算机及柜员终
端组成的网络系统。中央计算机由总行投
资购买。分行负责提供分行计算机和柜员
终端。柜员终端设在分行下属的储蓄所内。
该系统的软件开发成本由各分行分摊。
储户凭存折向银行柜员要求进行存款或
取款,取款时还必须提供密码。柜员负责
把储户提交的存款或取款信息输进柜员终
端,接收储户交来的现金或支票,或付给
储户现金。柜员终端与相应的分行计算机
通信,分行计算机具体处理针对某个帐户
的事务并且维护帐户。如果是初次存款,
则系统开立一个新帐户,并记录存款人姓
名、住址、身份证号码、存款日期、存款
金额、密码等信息,并给用户一个存折。
帐户中的余额至少要留 10元钱,如果全部
取完,则系统撤销该帐户。
下面根据该需求陈述,通过五个活动建
立, 储蓄系统, 的对象模型。作为一个例
子,该对象模型中所考虑的情况比较简单,
实际的情况要复杂的多。
(一 )识别类 —&—对象
面向对象方法是围绕着对象进行的,所
以类 —&—对象的选择是最关键的一步。
类 —&—对象选择得好,一方面可以便于程
序的扩充,另一方面还可以为以后的其它
应用提供基础。类 —&—对象的确定可以根
据问题描述进行查找,然后根据一定的原
则进行筛选,最后给每一个类 —&—对象起
一个适当的名字用图形把它表示出来。
1,查找侯选对象
主要是从问题域、系统边界来考虑各种能启
发自己发现对象的因素,找出可能有用的侯选对
象。问题域中启发分析员发现对象的因素包括:
人员、组织、物品、设备、事件、表格、结构等。
分析员应该观察并研究问题域本身,研究用户提
供的各种说明材料,可以请用户提供简单的报告,
并从专业书籍及相关书籍中找到该问题域的权威
描述,了解该领域的基本知识和术语,从中抽取
经常出现的名词,这些名词往往可以提供潜在对
象的一些启示。
还要考虑系统边界,启发分析员发现一
些与系统边界以外的活动者进行交互以及
处理系统对外接口的对象,考虑的因素包
括:人员、设备和外系统。
最简单的方法是阅读需求陈述,从中找
出名词。例如认真阅读, 储蓄系统, 的需
求陈述,从中找出如下名词:
银行,总行,分行,市,储蓄所,系统,
中央计算机,分行计算机,柜员终端,网
络,软件,成本,储户,存折,柜员,存
款事务,取款事务,密码,信息,现金,
支票,帐户,事务,姓名,住址,身份证
号码,存款日期,存款金额,余额,通信。
分析员还应该根据领域知识或常识进一
步把隐含的类提取出来。例如,在储蓄系
统的陈述中虽然没写, 事务日志,,, 通
信链路,,但是,根据领域知识和常识可
以知道,在储蓄系统中应该包含这两个实
体。当然,这种简单的方法所确定的侯选
者是非常不准确的,其中往往包含大量不
正确的或不必要的事物,还必须经过更进
一步的严格筛选。
2,筛选对象
筛选时主要依据下列标准,删除不正确
或不必要的对象:
(1)冗余 如果两个类表达了同样的信
息,则应该保留在此问题中最富于描述力
的名称。例如,,储蓄系统, 中,存折与
帐户,分别描述了相同的二类信息,因此,
应该去掉, 存折, 冗余类,仅保留, 帐户,
类。
(2)无关 对照系统责任所要求的每一
项功能,如系统安装、配臵、信息备份、
浏览等,查看是否可以由现有的对象完成
这些功能。如果发现某些功能在现有的任
何对象中都不能提供,则可启发发现问题
域中某些遗漏的对象。
OOA用对象映射问题域中的事物,并不
意味着对分析员见到的任何东西都在系统
中设立相应的对象。 OOA需要正确运用抽象
的原则,即紧紧围绕系统责任这个目标去
进行抽象。
首先要舍弃那些与系统责任无关的事物,
只注意与系统责任有关的事物;其次,对
于与系统有关的事物,也不是把它们的任
何特征都在相应的对象中表达出来,而要
舍弃那些与系统特征无关的特征。判断事
物是否与系统责任有关的关键问题,一是
该事物是否围系统提供了一些有用的信息,
或者它是否需要系统为它保存和管理某些
信息;二是它是否向系统提供了某些服务,
或者它是否需要系统描述它的某些行为。
例如:当开发一个图书馆管理系统时,
设立了, 书, 这个类,同时把每一本书作为
该类的一个对象。这样做时正确的,因为系
统需要记住每一本书借给了哪个读者。但是
在开发一个书店的业务管理系统时,是否要
把每一本书作为一个对象呢?实际上,在这
个系统中把同一版本的一种书从总体上看作
一个对象更合理些。因为该系统只要把每种
书看作一项货物,记住它的货源、单价、库
存量等信息就够了,不需记录每一本书的信
息。
“储蓄系统, 中,并不处理分摊软件开
发成本的问题,应该去掉侯选类, 成本, 。
该系统的处理与储蓄所的地点无关,应该
去掉侯选类, 市, 。
(3)笼统 在需求陈述中常常使用一些笼统的、
泛指的名词,虽然在初步分析时把它们作为侯选
对象列出来,但是,要么系统无须记忆有关它们
的信息,要么在需求陈述中有更明确更具体的名
词对应它们所暗示的事务,因此,通常把这些笼
统的或模糊的类去掉。以储蓄系统为例,,银行,
实际指总行或分行,,信息, 的具体内容在需求
陈述中随后就指明了。因此,在本例中应该去掉
,银行,,, 网络,,, 系统,,, 软件,,
,信息,,, 事务, 等侯选类。
(4)属性 某些名词描述的是其它对象
的属性,如储蓄系统中, 现金,,, 支
票,,, 存款金额,,, 余额,,, 密
码,,, 姓名,,, 住址,,, 身份证号
码,,, 存款日期, 等,实际上都应该作
为属性对待。当然,如果某个性质具有很
强的独立性,则应把它作为类而不是作为
属性。
(5)操作 在需求陈述中可能使用一些既可作
为名词,又可作为动词的词,应该慎重考虑它们
在本问题中的含义,以便正确地决定把它们作为
类还是作为类中定义的操作。例如,谈到电话时
通常把, 拨号, 当作动词,当构造电话模型时确
实把它作为一个操作,而不是一个类。但是,在
开发电话的自动记帐系统时,,拨号, 需要有自
己的属性(例如日期、时间、受话地点等),因
此把它作为一个类。总之,本身具有属性需独立
存在的操作,应该作为类 —&—对象,反之,则
作为对象的操作。分析储蓄系统中可以去掉, 通
信, 。
(6)实现 在分析阶段不应该过早地考虑怎样
实现目标系统,因此应该去掉仅和实现有关的侯
选类。这些类在设计和实现阶段可能是重要的,
但在分析阶段过早地考虑它们反而会分散我们的
注意力。在, 储蓄系统, 中,,事务日志, 无非
是对一系列事务的记录,它的确切表示方式是面
向对象设计的议题;, 通信链路, 在逻辑上是一
种联系,在系统实现时它是关联链的物理实现。
总之,应该暂时去掉这两个类,在设计或实现时
再考虑它们。
3,对象命名及, 类 —&—对象, 层
的建立
通过以上的处理,系统中需要设臵的
类 —&—对象基本明确(在以后的 OOA活动
中可能有调整)。最后,还要仔细推敲每
个类的命名。类的命名应该采用恰好符合
这个类所包含每一个对象的名词或带有定
语的名词,要使用专家及用户惯常使用的
规范的词汇。
中国的软件开发者为国内用户开发的软
件,在 OOA与 OOD文档中使用中文无疑最有
利于表达和交流,但类及其属性和服务的
命名使用英文有利于与程序的对应。理想
的软件工具能同时支持两种文字,如果缺
少这种支持工具,则可以在 OOA与 OOD文档
中使用中文,同时建立一个中、英文命名
对照表以便与程序对应。类名确定之后,
用适当的图形表示出来。
储蓄系统中,经过筛选,剩下图 7,7所
示的类 —&—对象,用图形方式表示出来,
组成储蓄系统的类 —&—对象层。
注意,一个对象的完整定义除了对象名
还有属性和服务,要等到后几个步骤完成
后才能得到。
储蓄系统对象模型类 —&—对象层
储户
帐户
存款事务 总行
分行 中央
计算机
储蓄所 分行
计算机
终端
柜员
存款事务
(二 )识别结构
面向对象中,结构表示了问题域中的复
杂关系,是对客观世界实体相互间关系的
抽象。需求陈述中使用的描述性动词或动
词词组,通常表示对象之间的关系,例如
,总行下设几个分行, 表示了总行和分行
之间的组装关系。仔细分析需求陈述,并
与用户及领域专家讨论,确定结构关系。
下图是储蓄系统的对象模型结构层,表
明一个总行由一个中央计算机和多个分行
组成,一个分行由一个分行计算机和多个
储蓄所组成,一个储蓄所由多个终端和多
个柜员组成。
储蓄系统对象模型结构层
储户
帐户
取款事务 总行
分行 中央
计算机
储蓄所 分行
计算机
终端 柜员
1+
1+
1+ 1+
存款事务
(三 )识别主题
为了理解复杂的系统,可以将大系统分解为
几个主题。当然在开发很小的系统时,可能无须
引入主题层。
主题层的划分原则是:应该按问题域而不是
用功能分解方法来确定主题,组合结构常常可以
形成一个主题。图 7.9表示储蓄系统的主题层,
将储蓄系统分解为三个主题:储户、事务、银行,
分别用三个粗黑框封闭起来,右下角是主题名。
储户
帐户
取款事务 总行
分行 中央计算机
储蓄所 分行
计算机
终端 柜员
储户 事务
银行
储蓄系统对象模型主题层
存款事务
1+
1+
1+
1+
(四 )定义属性
属性是对象的性质,籍助于属性我们能对类、
对象和结构有更深入更具体的认识。定义属性过
程要完成如下几件事:
1.标识属性及定位 分析员需要回到问题空
间的描述与用户交流,找出适用于每个类 —&—
对象的属性。通常在需求陈述中,用名词词组表
示属性,如, 汽车的颜色,,, 光标的位臵, 。
找到属性之后,利用分类结构中的继承机制确定
属性的位臵。如果某个属性可适用于绝大多数的
特殊情况,则可将属性放在通用的位臵上。
2,修订对象 随着属性的增加,对对
象及结构的认识更加具体,可能需要重新
修订一些对象或分类结构。一般从以下角
度来检验:
(1)带有, 非法, 值的属性 如果某些
属性不适合于一个对象的所有实例或分类
结构的某个特定的实例,则应该考虑引入
附加的分类结构。
(2)单个属性 如果对象或分类结构的
实例只有一个属性,则应该考虑将单个的
属性直接放入与该属性所描述的对象相关
联的更高一层的对象,然后删除这个多余
的对象。例如考虑将, 总行计算机, 和
,总行, 合并,,分行计算机, 和, 分行,
合并。
(3) 识别继承 对系统中众多的类加
以组织,将有共同属性的类抽取共性,建
立通用类。例如,,存款事务,,, 取款
事务, 有些属性是相同的,增加一个类
,事务, 。
(4)属性值的冗余 一个对象实例的某
个属性可能有多个重复值,此时则应考虑
增加新的对象。
3.建立实例连接 深入考察问题域,了解事
务规则,从中寻找对象之间存在的关系,建立实
例连接。在进行连接时,要努力获得最少的必要
的连接集合。如果连接适合于所有对象,则在分
类结构的通用层相连接,否则只能在特殊的专用
层连接。下图是储蓄系统对象模型属性层,为了
更清楚表明各实例之间存在着的是什么样的关系,
可以在实例连接线上注明,大家仔细看图,可以
理解它们之间的关系。
储户
姓名
地址
帐户
帐户号
余额
事务
日期
金额
柜员号
1+
1+
取款事务
总行
名称
柜员
柜员号
储蓄所
所号
地址1+
分行
分行号1+
1+
1+
储蓄系统对象模型属性层
存款事务
终端
终端

1+
1+
1+
存储
要求
拥有 处理
存储
(五 )定义服务和消息连接
分析员通过分析对象的行为来定义对象
的每个服务。通常在完整地定义每个类中
的服务和消息连接之前,需要先建立起动
态模型和功能模型。通过对这两种模型的
研究,能够更正确更合理地确定每个类应
该提供哪些服务、每个服务的处理过程是
什么以及对象之间应该具有怎样的消息连
接。
第二节 动态模型的建立
动态模型通过描绘系统与用户发生交互
时的各种情形,决定每个类需有的操作以
及对象之间的通信关系。每个类的动态行
为用一张状态图来描绘,各个类的状态图
合并起来,构成系统的动态模型。
一、状态、事件、行为
对象的行为规则往往与对象的状态有关,
对象状态是对象中影响对象行为的属性值
的抽象。认识和区别对象的状态应着眼于
它对对象行为的不同影响,仅当对象的行
为规则有所不同时,才认为对象处于不同
的状态。
例如, 栈,,假如它的属性数据是 1000
个存储单元( 1-1000)和一个栈顶指针,
行为有, 压入, 和, 弹出, 。不考虑每个
存储单元所存储的数据值的差别,仅考虑
指针所指的存储单元,属性值的变化就有
1001(从 0到 1000)种情况。但其中引起行
为变化的只有三种情形:空(指针值 =0)、
满(指针值 =1000)、半满( 0<指针值
<1000)。因此可以认为, 栈, 对象只有三
种状态。
这三种状态影响, 栈, 行为规则的不同如
下表所示
状态
行为
空 半满 满
压入 可执行 可执行 不可执行
弹出 不可执行 可执行 可执行
事件是指某个特定时刻所发生的引起对象状
态转换的事情。事件没有持续时间,是瞬间完成
的。例如 21次列车到达上海之前必须离开北京,
这里有两个事件, 列车到达上海, 和, 列车从北
京出发, 。每个事件是单独发生的,事件有发送
对象和接收对象,但发送对象和接收对象可以相
同。
行为是指对象内部为达到某种状态所做的
一系列处理, 这些处理是需要耗费时间的 。
状态, 事件, 行为三者之间的关系及图形符
号如图所示 。
状态 1
do:行为 1
状态 2
do:行为 2
初始事件 事件 1[条件 1] 结束事件
状态用圆形框或椭圆框表示,框内可标
上状态名也可不给状态起名字,行为在框
内用关键字 do:标明。从一个状态到另一
个状态的转换用箭头表示,箭头线上标以
事件名。必要时可在事件名后面加一个方
括号,括号内写上状态转换的条件。也就
是说,仅当方括号内所列出的条件为真时,
该事件的发生才引起所示的状态转换。实
心圆表示初始状态,环形圆表示最终状态。
该图同时也表示了状态、事件、行为三者之
间的关系,状态的改变是由事件的发生引起的,
对象必须通过内部的某些行为(操作)才能达到
对象状态的改变。这是对象封装性的特征,对象
内部状态的细节是隐藏的,外部无法知道,也无
法改变,只能通过对象内部的操作改变。状态、
事件以及行为的具体确定,需要通过详细描述系
统与用户的交互过程。
二、系统与用户交互过程描述
虽然在需求陈述中表明了从用户那里应
该获取的有关信息,但并没有准确说明获
取信息的具体过程,对动作次序的要求也
是模糊的。通过描述用户与系统的一个或
多个典型交互过程,帮助对目标系统的行
为有更具体的认识。描述过程中,应注意
交代动作的主动者和接收者。通常应描述
各种交互情形,包括, 正常情形的说明,
在编写的过程中,需要与用户充分交换
意见,编写之后还应该经过他们的审查与
修改。表 7-2给出储蓄系统中一个正常情形
的说明,而表 7-3给出了一个非正常情形的
说明。
储户将存折交给柜员, 柜员将存折号输入终端 。
终端向分行请求验证存折是否有效, 分行验证后通知终端说该存折有效 。
柜员询问事务类型, 储户请求取款事务, 柜员输入取款事务 。
终端要求储户输入密码, 储户输入密码, 1234”等数字 。
终端请求分行验证密码, 分行核对后通知终端说密码有效 。
柜员询问储户取款额, 并输入终端 。
终端确认取款额在预先规定的限额内, 要求分行处理这个取款事务 。
分行处理更新帐户, 处理完毕, 终端打印处理帐单 。
柜员将帐单交给储户核对, 储户核对后签字 。
柜员将现金交还给储户, 储户核对现金 。
柜员将存折还给储户 。
储蓄系统正常情形的说明
储户将存折交给柜员, 柜员将存折号输入终端 。
终端向分行请求验证存折是否有效, 分行验证后通知柜员终端说该存折无效 。
储户更换存折, 分行验证后通知终端说该存折有效 。
柜员询问事务类型, 储户要求取款事务, 柜员输入取款事务 。
终端要求储户输入密码, 储户误输入密码, 1111”等数字 。
终端请求分行验证密码, 分行核对后通知终端说密码无效 。
终端请储户重新输入密码;储户输入, 1234”后, 系统验证后通知终端密码有效 。
柜员询问储户取款额, 并输入终端 。
储户的取款额超过限额, 终端要求重新输入取款额 。
储户改变主意不想取款了, 终端取消该事务 。
柜员将存折还给储户 。
储蓄系统非正常情形的说明
三、确定事件
仔细分析系统与用户的交互过程,从中
提取事件。事件包括系统与用户(或外部
设备)交互的所有信号、输入、输出、中
断、动作等;对象之间信息传递的动作也
是事件,如储户输入密码。对每一个事件
取适当的名字,区分事件的执行顺序以及
事件的发送对象和接收对象,确定事件与
对象之间的关系。
可以用事件跟踪图把事件序列以及事件
与对象之间的关系形象、清晰地表示出来。
下图是, 储蓄系统, 正常情况下的事件跟
踪图(为简单起见,未考虑与总行的交互
过程)。竖线表示对象,水平箭头线表示
事件,按执行顺序从上到下排列。
储蓄系统正常情况下的事件跟踪图
询问类型
储户 柜员 终端 分行
请求验证帐户递交存折 请求分行验证帐户
帐户有效要求类型
要求输入密码
输入密码 请求分行验证密码
密码有效
输入取款额
要求输入取款额
请求分行处理事务
分行事务成功帐单打印请求帐单确认
帐单签字确认
交现金, 还存折
输入类型回答类型
询问取款额
回答取款额
四、画状态图
一张状态图描绘一类对象的行为、事件
与对象状态的关系。画状态图的方法是:
1、选定一张事件跟踪图出发,仅考虑
事件跟踪图中指向某条竖线的那些箭头线,
把这些事件作为状态图中的箭头线,箭头
线上标以事件名。两个事件之间的间隔就
是类的两个状态(如果一个事件并不引起
当前状态的改变,则可以忽略这个事件),
应该尽量给每个状态取个名字。从事件跟
踪图中当前考虑的竖线射出的箭头线,是
2、把其它的事件跟踪图合并到已画出
的状态图中,找出分支点(例如, 验证帐
户, 就是分支点,因为验证的结果可能是
,帐户有效,,也可能是, 帐户无效, ),
然后把其它事件跟踪图中对应的事件序列
并入已有的状态图中,作为一条可选的路
径。
3、考虑边界情况和特殊情况,例如有时用户
(或外部设备)不能做出快速响应,然而某些资
源又必须及时收回,于是在一定间隔后就产生了
,超时, 事件。这类出错情况的处理往往需要花
费很多精力,并且会使原来清晰、紧凑的程序结
构变得复杂、繁琐,因此可以放在最后加以考虑,
但不能省略。
当考虑完所有的情况,该类的状态图就
构造出来了,与用户讨论,反复检查这张
状态图,多问几个, 如果 ……,则 ……” 的
问题,避免遗漏一些情况。
并不是每一个类都要画状态图,系统分
析员应集中精力仅考虑具有重要交互行为
的那些类。本例中,,终端,,, 分行,
是主动对象,它们相互发送事件;而, 事
务,,, 帐户, 是被动对象,并不发送事
件。, 储户,,, 柜员, 虽然也是动作对
象,但是,它们都是系统外面的因素,无
“柜员终端”状态图
请求验证帐户主屏
do:显示主屏幕
do:要求密码
帐户有效
do:验证密码
输入密码
密码正确处理结束
结束
do:打印帐单
do:验证帐户
do:显示无效帐户
帐户无效
密码错
取款额无效
do:要求取款额do:检验取款额取款额有效do:取款事务
do:显示取消信息
do:要求类型
输入类型
输入取款额
do:显示失败信息
事务失败
等待 5秒钟
取消
取消
取消
取消
“分行”状态图
[无效 ]
请求分行验证帐户
do:验证帐户
请求分行验证密码
do:验证密码
请求分行处理事务
do:更新帐户
[有效 ] [错误 ][正确 ] [失败 ][成功 ]
五、审查动态模型
各个类的状态图通过共享事件合并起来,构成
了系统的动态模型。在完成了每个重要交互行为的
类的状态图之后,应该检查系统级的完整性和一致
性。要审查每个事件和状态,考察每个事件是不是
既有发送者又有接受者(有时发送者和接受者是同
一个对象)。跟踪每个事件对系统中各个对象所产
生的效果,检查是否与交互过程一致。考察每个状
态,如果该状态不是交互序列的起点或终点,应该
有前驱和后继的状态,否则就出错了。审查之后,
该系统的动态模型就建立起来了。
第三节 功能模型的建立
从功能角度比较,对象模型定义, 谁做或对
谁做,,动态模型定义, 何时做,,而功能模型
要定义, 做什么, 。也就是功能模型是决定各个
对象在不考虑动作次序的情况下,如何进行各种
不同的动作操作,数据是如何在各操作中流动。
功能模型由分层数据流图组成,下层数据流图是
上层数据流图中功能的分解,直至该功能能够容
易实现。
通过数据字典对数据和功能进行描述,
数据流不指出控制或对象的结构信息,他
们包含在动态模型和对象模型中。图( a)
表明顶层数据流图,图( b)是 0层数据流
图,实际的情形还应该继续细化。
( a)
金额
帐号
柜员储户 储蓄系统
事务类型
现金, 帐单
密码
( b)
储蓄系统功能模型
正确帐号验证帐户帐号
检验取款额更新帐户 金额正确取款额帐单, 现金
帐户
类型选择
事务类型
取款事务
密码
正确密码
储户
验证密码
功能模型说明了从外部输入,通过操作
和内部存储,直到外部输出,这整个的数
据流动情况,不考虑参加计算的数据按什
么时序执行。结构化范型中的 DFD与功能模
型基本一致,差别在于数据存储。在结构
化范型中,数据存储将几乎肯定当作文件
来保存。然而,一个类的状态变量也是数
据存储。因此,功能模型包含两类数据存
储,即类的存储和不属于类的数据存储。
第四节 定义服务
完整的对象是由属性和服务构成的整体。在
建立了动态模型和功能模型后,现在可以从中确
定对象的服务以及对象之间的消息连接,从而建
立对象模型的服务层。
一、服务分类
为了明确 OOA应该定义对象哪些服务,首先区
分一下对象服务的不同类别。
(一 ) 系统服务
与对象有关的某些行为实际上不是
对象自身的行为,而是系统把对象看作一
个整体来处理时施加于对象的行为。例如,
对象的创建、复制、存储到外存、从外存
恢复、删除等等。对于这类行为除非有特
别的要求,OOA一般不必为之定义相应的服
务。
(二 ) 常规服务
按照严格的封装原则,任何读、写
对象属性的操作都不能从对象外部直接进
行,而应由对象中相应的服务完成。这样
在实现每个对象时就需要在每个对象中设
立许多这样的服务。其算法十分简单,只
是读取或设臵一个属性的值,这是对象自
身的行为。此类的服务是常规服务,通常
无须在对象图中显式表示这些常规操作。
(三 ) 算法复杂的服务
此类对象描述了对象所映射事物的固有
行为,其算法不是简单地读或写一个属性
值,而要进行某些计算或监控操作。例如
对某些属性的值进行计算得到某种结果,
对数据进行加工处理,对设备或外系统进
行监控并处理输入、输出信息等等。这类
服务需仔细研究动态模型和功能模型,从
中寻找服务并在服务层表示该服务。
二、发现服务的策略与启发
(一 )从类的状态图及数据流图寻找类的服

状态图中对象的行为能改变对象的状态,
这些行为通常就是对象必须提供的操作。分
层数据流图中的每个处理框的逐步分解对应
着一个对象(也可能是若干个对象)上的操
作细化过程。应该仔细对照状态图和数据流
图,以便更正确地确定对象应该提供的服务。
(二 )利用继承减少冗余操作
应该尽量利用继承机制以减少所需
定义的服务数目。只要不违背领域知识和
常识,就尽量抽取出类似类的公共属性和
操作,可能要修改对象层以建立这些类的
新父类,并在类等级的不同层次中正确地
定义各个服务。
三、建立消息连接
动态模型中通过共享事件连接,这些共
享事件的存在往往反映了对象之间需要进
行的消息连接。
图表明储蓄系统的服务层。
储蓄系统对象模型服务层
储户
姓名
地址
帐户
帐户号
余额
事务
日期
金额
柜员号
1+
1+
取款事务
取款
总行
名称
柜员
柜员号 储蓄所
所号
地址1+
分行
分行号
验证帐号
验证密码
更新帐户
1+
1+
1+
存款事务
存款
1+
1+
终端
终端号
验证帐号
验证密码
打印帐单
总之,面向对象强调对, 现实世界, 的
模型化,这里, 现实世界, 是指所面对的
实际应用问题。即就是说,通过一系列的
活动建立起的分析模型就是对实际问题的
抽象。在概念上可以认为面向对象分析大
体上按照下列顺序进行:寻找类 —&—对象,
识别结构,识别主题,定义属性,建立动
态模型,建立功能模型,定义服务。
面向对象技术并不强调严格按步骤进行,
在初步确定类 —&—对象层之后,随着对问
题的理解逐步深入,会回到类 —&—对象层
进行修改。分析员建立起分析模型后,必
须与用户及领域专家反复交流、多次磋商,
及时纠正错误认识并补充缺少的信息,其
中往往需要利用原型系统作为辅助工具。