ATM机的面向对象分析--笔记
流程:
“对象”是由描述其属性的数据,及可以对这些数据施加的操作(即服务),封装在一起构成的独立单元。
一、抽象出对象和对象之间的关联
二、画静态模型
1、画出关联图
2、划分主题
3、为关联图中的对象添加属性
4、识别继承关系
5、反复修改,比如把关联时传递的动作信息进行对象化
三、画动态模型
建立动态模型的第一步,是编写典型交互行为的脚本。虽然脚本中不可能包括每个偶然事件,但是,至少必须保证不遗漏常见的交互行为。
接下来从脚本中提取出事件,确定触发每个事件的动作对象以及接受事件的目标对象。
第三步,排列事件发生的次序,确定每个对象可能有的状态及状态间的转换关系,并用状态图描绘它们。
1、编写典型交互行为的脚本,脚本是指系统在某一执行期间内出现的一系列事件。虽然脚本中不可能包括每个偶然事件,但是,至少必须保证不遗漏常见的交互行为。
2、应该仔细分析每个脚本,确定触发每个事件的动作对象以及接受事件的目标对象。
3、分析每个事件的处理过程,画事件跟踪图
4、排列事件发生的次序,确定每个对象可能有的状态及状态间的转换关系,画状态图
4、如果有需要,可以画时序图
四、画功能模型
1、画出基本系统模型图
2、得到功能级数据流图(把基本系统模型中单一的处理框分解成若干个处理框,以描述系统加工、变换数据的基本功能)
一、定义使用场景
OOA过程并不是从考虑对象开始,而是从理解系统的使用方式开始,
如果系统是人机交互的,则考虑被人使用的方式;
如果是设计过程控制的,则考虑被机器使用的方式;
如果是系统协调和控制应用,则考虑被其他程序使用的方式
面向对象分析(通常缩写为OOA)的关键,是识别出问题域内的对象,并分析它们相互间的关系,最终建立起问题域的简洁、精确、可理解的正确模型。
面向对象分析,就是抽取和整理用户需求并建立问题域精确模型的过程。
三个子模型与五个层次
面向对象建模得到的模型包含对象的三个要素,即静态结构(对象模型),交互次序(动态模型)和数据变换(功能模型)。
解决的问题不同,这三个子模型的重要程度也不同:
几乎解决任何一个问题,都需要从客观世界实体及实体间相互关系抽象出极有价值的对象模型;
当问题涉及交互作用和时序时(例如,用户界面及过程控制等),动态模型是重要的;
解决运算量很大的问题(例如,高级语言编译、科学与工程计算等),则涉及重要的功能模型。
动态l模型和功能模型中都包含了对象模型中的操作(即服务或方法)。
复杂问题(大型系统)的对象模型由下述五个层次组成:主题层(也称为范畴层)、类一&一对象层、结构层、属性层和服务层。
面向对象分析大体上按照下列顺序进行:寻找类一&一对象,识别结构,识别主题,定义属性,建立动态模型,建立功能模型,定义服务。
但是,正如前面已经多次强调指出过的,分析不可能严格地按照预定顺序进行,大型、复杂系统的模型需要反复构造多遍才能建成。
通常,先构造出模型的子集,然后再逐渐扩充,直到完全、充分地理解了整个问题,才能最终把模型建立起来。
通常,需求陈述的内容包括:问题范围,功能需求,性能需求,应用环境及假设条件等。总之,需求陈述应该阐明“做什么”而不是“怎样做”。
如图所示的自动取款机(ATM)系统,是讲述面向对象分析和面向对象设计时使用的一个实例。
下面陈述对ATM系统的需求:
某银行拟开发一个自动取款机系统,它是一个由自动取款机、中央计算机、分行计算机及柜员终端组成的网络系统。
ATM和中央计算机由总行投资购买。总行拥有多台 ATM,分别设在全市各主要街道上。分行负责提供分行计算机和柜员终端。
柜员终端设在分行营业厅及分行下属的各个储蓄所内。该系统的软件开发成本由各个分行分摊。
银行柜员使用柜员终端处理储户提交的储蓄事务。储户可以用现金或支票向自己拥有的某个账户内存款或开新账户。
储户也可以从自己的账户中取款。通常,一个储户可能拥有多个账户。
柜员负责把储户提交的存款或取款事务输进柜员终端,接收储户交来的现金或支票,或付给储户现金。
柜员终端与相应的分行计算机通信,分行计算机具体处理针对某个账户的事务并且维护账户。
拥有银行账户的储户有权申请领取现金兑换卡。使用现金兑换卡可以通过ATM访问自己的账户。
目前仅限于用现金兑换卡在ATM上提取现金(即取款),或查询有关自己账户的信息(例如,某个指定账户上的余额)。
将来可能还要求使用ATM办理转账、存款等事务。
所谓现金兑换卡就是一张特制的磁卡,上面有分行代码和卡号。
分行代码唯一标识总行下属的一个分行,卡号确定了这张卡可以访问哪些账户。
通常,一张卡可以访问储户的若干个账户,但是不一定能访问这个储户的全部账户。
每张现金兑换卡仅属于一个储户所有,但是,同一张卡可能有多个副本,因此,必须考虑同时在若干台ATM上使用同样的现金兑换卡的可能性。
也就是说,系统应该能够处理并发的访问。
当用户把现金兑换卡插入ATM之后,ATM就与用户交互,以获取有关这次事务的信息,并与中央计算机交换关于事务的信息。
首先,ATM要求用户输入密码,接下来ATM把从这张卡上读到的信息以及用户输入的密码传给中央计算机,请求中央计算机核对这些信息并处理这次事务。
中央计算机根据卡上的分行代码确定这次事务与分行的对应关系,并且委托相应的分行计算机验证用户密码。
如果用户输入的密码是正确的,ATM就要求用户选择事务类型(取款、查询等)。
当用户选择取款时,ATM请求用户输入取款额。最后,ATM从现金出口吐出现金,并且打印出账单交给用户。
建立对象摸型
对象模型通常有五个层次。
典型的工作步骤是,
首先确定对象类和关联(因为它们影响系统整体结构和解决问题的方法),对于大型复杂问题还要进一步划分出若干个主题;
然后给类和关联增添属性,以进一步描述它们;
接下来利用适当的继承关系进一步合并和组织类。
而对类中操作的最后确定,则需等到建立了动态模型和功能模型之后,因为这两个子模型更准确地描述了对类中提供的服务的需求。
什么是对象?什么可以抽象为对象?
什么都可以。
通常,
对象是对问题域中有意义的事物的抽象,它们既可能是物理实体,也可能是抽象概念。·具体地说,大多数客观事物可分为下述五类
(1)可感知的物理实体,例如,飞机、汽车、书、房屋等等。
(2)人或组织的角色,例如,医生、教师、雇主、雇员、计算机系、财务处等等。
(3)应该记忆的事件,例如,飞行、演出、访问、交通事故等等。
(4)两个或多个对象的相互作用,通常具有交易或接触的性质,例如,购买、纳税、结婚等等。
(5)需要说明的概念,例如,政策、保险政策、版权法等等。
另一种更简单的分析方法,是所谓的非正式分析。这种分析方法以用自然语言书写的 需求陈述为依据,把陈述中的名词作为类一&一对象的候选者,用形容词作为确定属性的线索,把动词作为服务(操作)的候选者。
认真阅读上面给出的需求陈述,从陈述中找出下列名词,可以把它们作为类一&-一对象的初步的候选者:
银行,自动取款机(ATM),系统,中央计算机,分行计算机,柜员终端,网络,总行,分行,软件,成本,市,街道,营业厅,储蓄所,柜员,储户,现金,支票,账户,事务,现金兑换卡,余额,磁卡,分行代码,卡号,用户,副本,信息,密码,类型,取款额,账单,访问。
2.筛选出正确的类一&一对象
接下来应该严格考察每个候选对象,从中去掉不正确的或不必要的,仅保留确实应该记录其信息或需要其提供服务的那些对象。
筛选时主要依据下列标准,删除不正确或不必要的类一&一对象:
(l)冗余
如果两个类表达了同样的信息,则应该保留在此问题域中最富于描述力的名称。
以ATM系统为例,应该去掉“用户”、“磁卡”、“副
本”等冗余的类,仅保留“储户”和“现金兑换卡”这两个类。
(2)无关
仅需要把与本问题密切相关的类一&一对象放进目标系统中。
以ATM系统为例,因此,应该去掉候选类“成本”、“市”、“街道”、“营业厅”和“储蓄所”。
(3)笼统
在需求陈述中常常使用一些笼统的、泛指的名词,虽然在初步分析时把它们作为候选的类一&一对象列出来了,但是,要么系统无须记忆有关它们的信息,要么在需求陈述中有更明确更具体的名词对应它们所暗示的事务,因此,通常把这些笼统的或模糊的类去掉。
以ATM系统为例,应该去掉“银行”、“网络”、“系统”、“软件”、“信息”、“访问”等候选类。
(4)属性
在需求陈述中有些名词实际上描述的是其他对象的属性,应该把这些名词从候选类一&一对象中去掉。
在ATM系统的例子中,“现金”、“支票”、“取款额”、“账单”、“余额”、“分行代码”、“卡号”、“密码”、“类型”等,实际上都应该作为属性对待。
(5)操作
在需求陈述中有时可能使用一些既可作为名词,又可作为动词的词,应该慎重考虑它们在本问题中的含义,以便正确地决定把它们作为类还是作为类中定义的操作。
(6)实现
在分析阶段不应该过早地考虑怎样实现目标系统。因此,应该去掉仅和实现有关的候选的类一&一对象。
在ATM系统的例子中,应该暂时去掉“事务日志”和“通信链路”这两个类,在设计或实现时再考虑它们。
3.3. 2 确定关联
多数人习惯于在初步分析确定了问题域中的类一&一对象之后,接下来就分析确定类一&一对象之间存在的关联关系。
两个或多个对象之间的相互依赖、相互作用的关系就是关联。分析确定关联,能促使分析员考虑问题域的边缘情况,有助于发现那些尚未被发现的类一&一对象。
1.初步确定关联
在需求陈述中使用的描述性动词或动词词组,通常表示关联关系。因此,在初步确定关联时,大多数关联可以通过直接提取需求陈述中的动词词组而得出。通过分析需求陈述,还能发现一些在陈述中隐含的关联。
以ATM系统为例,经过分析初步确定出下列关联:
(l)直接提取动词短语得出的关联
·ATM、中央计算机、分行计算机及柜员终端组成网络。
·总行拥有多台ATM。
·ATM设在主要街道上。
·分行提供分行计算机和柜员终端。
·柜员终端设在分行营业厅及储蓄所内。
·分行分摊软件开发成本。
·储户拥有账户。
·分行计算机处理针对账户的事务。
·分行计算机维护账户。
·柜员终端与分行计算机通信。
·柜员输入针对账户的事务。
· ATM与中央计算机交换关于事务的信息。
·中央计算机确定事务与分行的对应关系。
· ATM读现金兑换卡。
·ATM与用户交互。
·ATM吐出现金。
. ATM打印账单。
·系统处理并发的访问。
(2)需求陈述中隐含的关联
·总行由各个分行组成。
·分行保管账户。
·总行拥有中央计算机。
·系统维护事务日志。
·系统提供必要的安全性。
·储户拥有现金兑换卡。
(3)根据问题域知识得出的关联
·现金兑换卡访问账户。
·分行雇用柜员。
2.筛选
经初步分析得出的关联只能作为候选的关联,还需经过进一步筛选,以去掉不正确的或不必要的关联。筛选时主要根据下述标准删除候选的关联:
(1)已删去的类之间的关联。
如果在分析确定类一&一对象的过程中已经测掉了某个候选类,则与这个类有关的关联也应该删去。
以ATM系统为例,由于已经删去了“系统”、“网络”、“市”、“街道”、“成本”、“软件”、“事务日志”、“现金”、“营业厅”、“储蓄所”、“账单”等候选类,因此,与这些类有关的下列入个关联也应该删去:
①ATM、中央计算机、分行计算机及柜员终端组成网络。
②ATM设在主要街道上。
③分行分摊软件开发成本。
④系统提供必要的安全性。
⑤系统维护事务日志。
⑥ ATM吐出现金。
⑦ATM打印账单。
⑧柜员终端设在分行营业厅及储蓄所内。
(2)与问题无关的或应在实现阶段考虑的关联
应该把处在本问题域之外的关联或与实现密切相关的关联删去。
例如,在ATM系统的例子中,“系统处理并发的访问”并没有标明对象之间的新关联,它只不过提醒我们在实现阶段需要使用实现并发访问的算法,以处理并发事务。
(3)瞬时事件
关联应该描述问题域的静态结构,而不应该是一个瞬时事件。
以ATM系统为例,“ATM读现金兑换卡”描述了ATM与用户交互周期中的一个动作,它并不是ATM与现金兑换卡之间的固有关系,因此应该删去。类似地,还应该删去“ATM与用户交互”这个候选的关联。
(4)三元关联
三个或三个以上对象之间的关联,大多可以分解为二元关联或用词组描述成限定的关联。
在ATM系统的例子中,“柜员输入针对账户的事务”可以分解成“柜员输人事务”和“事务修改账户”这样两个二元关联。
(5)派生关联
应该去掉那些可以用其他关联定义的冗余关联。
例如,在ATM系统的例子中,“总行拥有多台 ATM”实质上是“总行拥有中央计算机”和“ATM与中央计算机通信”这两个关联组合的结果。而“分行计算机维护账户”的实际含义是,“分行保管账户”和“事务修改账户”。
派生关联是理解业务出现错误的原因之一。
3.进一步完善
应该进一步完善经筛选后余下的关联,通常从下述几个方面进行改进:
(1)正名
好的名字是帮助读者理解的关键因素之一。因此,应该仔细选择含义更明确的名字作为关联名。
(2)分解
为了能够适用于不同的关联,必要时应该分解以前确定的类一&一对象。
例如,在ATM系统中,应该把“事务”分解成“远程事务”和“柜员事务”。
(3)补充
发现了遗漏的关联就应该及时补上。
例如,在ATM系统中把“事务”分解成上述两类之后,需要补充“柜员输入柜员事务”、“柜员事务输进柜员终端”、“在ATM上输入远程事务”和“远程事务由现金兑换卡授权”等关联。
(4)标明阶数
应该初步判定各个关联的类型,并粗略地确定关联的阶数。
3.3.3 划分主题
在开发大型、复杂系统的过程中,为了降低复杂程度,人们习惯于把系统再进一步划分成几个不同的主题,也就是在概念上把系统包含的内容分解成若干个范畴。
应该按问题领域而不是用功能分解方法来确定主题。此外,应该按照使不同主题内的对象相互间依赖和交互最少的原则来确定主题。
以ATM系统为例,我们可以把它划分成“总行”、“分行”和“ATM”等三个主题,这三个主题的编号分别是l、2和3。
3.3 .4 确定属性
属性是对象的性质,藉助于属性我们能对类一&一对象和结构有更深入更具体的认识。注意,在分析阶段不要用属性来表示对象间的关系,使用关联能够表示两个对象间的任何关系,而且把关系表示得更清晰、更醒目。
一般说来,确定属性的过程包括分析和选择两个步骤。
1.分析
属性的确定既与问题域有关,也和目标系统的任务有关。应该仅考虑与具体应用直接相关的属性,不要考虑那些超出所要解决的问题范围的属性。在分析阶段不要考虑那些纯粹用于实现的属性。
2.选择
认真考察经初步分析而确定下来的那些属性,从中删掉不正确的或不必要的属性。通常有以下几种常见情况:
(l)误把对象当作属性
如果某个实体的独立存在比它的值更重要,则应把它作为一个对象而不是对象的属性。例如,在邮政目录中,“城市”是一个属性,而在人口普查中却应该把“城市”当作对象。
(2)把链属性误作为属性
如果某个性质依赖于某个关联链的存在,则该性质是链属性,在分析阶段不应该把它作为对象的属性。
(3)把限定误当成属性
限定是一种特殊的链属性。
在ATM系统的例子中,“分行代码”、“账号”、“雇员号”、“站号”等都是限定词。
(4)误把内部状态当成了属性
如果某个性质是对象的非公开的内部状态,则应该从对象模型中规掉这个属性。
(5)过于细化
在分析阶段应该忽略那些对大多数操作都没有影响的属性。
(6)存在不一致的属性
类应该是简单而且一致的。如果得出一些看起来与其他属性毫不相关的属性,则应该考虑把该类分解成两个不同的类。
经过筛选之后,得到ATM系统中各个类的属性,如图3.5所示。
我的理解是:如果某个属性下面有其他子属性,那么这个属性就可以单独拿出来当个对象。
3.3.5 识别继承关系
可以使用两种方式建立继承(即归纳)关系:
(1)自底向上:抽象出现有类的共同性质泛化出父类。例如,在ATM系统中,“远程事务”和“柜员事务”是类似的,可以泛化出父类“事务”;
(2)自须向下:把现有类细化成更具体的子类;
3.3.6 反复修改
仅仅经过一次建模过程很难得到完全正确的对象模型。事实上,软件开发过程就是一个多次反复修改、逐步完善的过程。在建模的任何一个步骤中,如果发现了模型的缺陷,都必须返回到前期阶段进行修改。
下面以ATM系统为例,讨论可能做的修改:
1.分解“现金兑换卡”类
把“现金兑换卡”类分解为“卡权限”和“现金兑换卡’两个类,将使每个类的功能更单一;
2.“事务”由“更新”组成
“更新”虽然代表一个动作,但是它有自己的属性(类型、金额等),应该独立存在,因此应该把它作为类一&一对象。
3.把“分行”与“分行计算机”合并
应该合并“分行”与“分行计算机”, “总行”和“中央计算机”
对于仅存储静态数据的系统(例如数据库)来说,动态模型并没有什么意义。然而在开发交互式系统时,动态模型却起着很重要的作用。如果收集输入信息是目标系统的一项主要工作,则在开发这类应用系统时建立正确的动态模型是至关重要的。
建立动态模型的第一步,是编写典型交互行为的脚本。虽然脚本中不可能包括每个偶然事件,但是,至少必须保证不遗漏常见的交互行为。
接下来从脚本中提取出事件,确定触发每个事件的动作对象以及接受事件的目标对象。
第三步,排列事件发生的次序,确定每个对象可能有的状态及状态间的转换关系,并用状态图描绘它们。
最后,比较各个对象的状态图,检查它们之间的一致性,确保事件之间的匹配。
3.4.1 编写脚本
在建立动态模型的过程中,脚本是指系统在某一执行期间内出现的一系列事件。脚本描述用户(或其他外部设备)与目标系统之间的一个或多个典型的交互过程,以便对目标系统的行为有更具体的认识。编写脚本的目的,是保证不遗漏重要的交互步骤,它有助于确保整个交互过程的正确性的和清晰性。
脚本描写的范围并不是固定的,既可以包括系统中发生的全部事件,也可以只包括由某些特定对象触发的事件。脚本描写的范围主要由编写脚本的具体目的决定。
编写脚本时,首先编写正常情况的脚本。然后,考虑特殊情况,最后,考虑出错情况。
对于每个事件,都应该指明触发该事件的动作对象(例如,系统、用户或其他外部事物)、接受事件的目标对象以及该事件的参数。
3.4.2 设想用户界面
大多数交互行为都可以分为应用逻辑和用户界面两部分。通常,系统分析员首先集中精力考虑系统的信息流和控制流,而不是首先考虑用户界面。应用逻辑是内在的、本质的内容,用户界面是外在的表现形式。动态模型着重表示应用系统的控制逻辑。
但是,用户界面的美观程度、方便程度、易学程度以及效率等等,是用户使用系统时最先感受到的,用户对系统的“第一印象”往往从界面得来,用户界面的好坏往往对用户是否喜欢、是否
接受一个系统起很重要的作用。因此,在分析阶段也不能完全忽略用户界面。
3.4.3 画事件跟踪图
为了有助于建立动态模型,通常在画状态图之前先画出事件跟踪图。为此首先需要进一步明确事件及事件与对象的关系。
1.确定事件
应该仔细分析每个脚本,以便从中提取出所有外部事件。事件包括系统与用户(或外部设备)交互的所有信号、输入、输出、中断、动作等等。
传递信息的对象的动作也是事件。例如,储户插入现金兑换卡、储户输入密码、ATM吐出现金等都是事件。大多数对象到对象的交互行为都对应着事件。
应该把对控制流产生相同效果的那些事件组合在一起作为一类事件,并给它们取一个唯一的名字。例如,“吐出现金”是一个事件类。
2.画出事件跟踪图
从脚本中提取出各类事件并确定了每类事件的发送对象和接受对象之后,就可以用事件跟踪图把事件序列以及事件与对象的关系,形象、清晰地表示出来。事件跟踪图实质上是扩充的脚本。
在事件跟踪图中,一条竖线代表一个类一&一对象,每个事件用一条水平的箭头线表示,箭头方向从事件的发送对象指向接受对象。时间从上向下递增。
3.4.4 画状态图
状态图描绘事件与对象状态的关系。当对象接受了一个事件以后,它的下个状态取决 于当前状态及所接受的事件。由事件引起的状态改变称为“转换”。如果一个事件并不引起当前状态发生转换,则可忽略这个事件。
通常,用一张状态图描绘一类对象的行为,它确定了由事件序列引出的状态序列。 考虑完正常事件之后再考虑边界情况和特殊情况,其中包括在不适当时候发生的事件(例如,系统正在处理某个事务时,用户要求取消该事务)。
3.4.5 审查动态模型
各个类的状态图通过共享事件合并起来,构成了系统的动态模型。在完成了每个具有重要交互行为的类的状态图之后,应该检查系统级的完整性和一致性。
应该审查每个事件,跟踪它对系统中各个对象所产生的效果,以保证它们与每个脚本都匹配。
3.5 建立功能摸型
功能模型表明了系统中数据之间的依赖关系,以及有关的数据处理功能,它由一组数据流图组成。
通常在建立了对象模型和动态模型之后再建立功能模型。
3.5.1 画出基本系统模型图
基本系统模型由若干个数据源点/终点,及一个处理框组成,这个处理框代表了系统加工、变换数据的整体功能。基本系统模型指明了目标系统的边界。由数据源点输入的数据和输出到数据终点的数据,是系统与外部世界之间的交互事件的参数。
3.5.2 画出功能级数据流图
把基本系统模型中单一的处理框分解成若干个处理框,以描述系统加工、变换数据的基本功能,就得到功能级数据流图。
3.5.3 描述处理框功能
把数据流图分解细化到一定程度之后,就应该描述图中各个处理框的功能。
“对象”是由描述其属性的数据,及可以对这些数据施加的操作(即服务),封装在一起构成的独立单元。因此,为建立完整的对象模型,既要确定类中应该定义的属性,又要确定类中应该定义的服务。前面已经指出,需要等到建立了动态模型和功能模型之后,才能最终确定类中应有的服务,因为这两个子模型更明确地描述了每个类中应该提供哪些服务。
3.6.1 常规行为
在分析阶段可以认为,类中定义的每个属性都是可以访问的。
3.6.2 从事件导出的操作
状态图中发往对象的事件也就是该对象接收到的消息,因此该对象必须有由消息选择符指定的操作,这个操作修改对象状态(即属性值)并启动相应的服务。
3.6.3 与数据流目中处理框对应的操作
数据流图中的每个处理框都与一个对象(也可能是若干个对象)上的操作相对应。
3.6.4 利用继承减少冗余操作
应该尽量利用继承机制以减少所需定义的服务数目。