7.2 系统分析方法
7.2.1 OOA过程模型面向对象分析需要将真实世界进行抽象,并加以描述。分析的目的是为了构造一个系统属性和系统行为的模型,该模型是根据对象和对象之间的关系、动态控制和功能转移来确定的。为此,OOA过程应该包含以下步骤:
(1)得到问题论域的初始化描述(问题叙述)。
(2)识别对象,定义它们的类。
(3)识别对象的内部特征,创建数据字典(包括类、属性和关系的描述)。
①定义属性
②定义服务
(4)识别对象的外部特征
①建立一般——特殊结构
②建立整体——部分结构
③建立实例连接
④建立消息连接
(5)划分主题,建立主题图。
(6)定义use case,建立交互图。
①发现活动者、系统边界。
②定义use case,反映怎样使用系统及系统向用户提供的功能。
③建立交互图。
(7)建立详细说明。
(8)原型开发。
注意:以上所列的OOA过程的各个步骤,并没有特定的次序要求,即允许各种活动交替进行(OOA方法的一个特点)。
考虑到各个步骤的特点及相互的衔接,对OOA过程的各活动安排给出一种建议,如图7.3。
以下将结合典型例子对面向对象分析过程的各个步骤的主要内容及主要方法进行讨论。
7.2.2 研究问题论域及用户需求
系统分析的基本出发点是问题论域及用户要求。在面向对象系统分析中,研究问题论域及用户需求的主要目的是通过对问题论域的深入研究,建立一个能够满足用户需求的系统模型。
面向对象分析的主要活动——发现对象、定义对象类等工作都要通过对问题论域的研究完成。对问题论域的研究一般可通过以下工作来完成:
(1)亲临现场,通过观察掌握第一手材料。
(2)认真听取问题论域专家的见解。
(3)阅读与问题论域有关的材料,学习相关领域的基本知识。
(4)借鉴相关或相似问题论域已有系统的OOA文档。
用户需求指的是用户对所要的开发的系统提出的各种要求和期望,包括系统的功能(着重考虑的)、性能、可靠性、保密要求、交互方式等技术要求和资金强度、交付时间、资源使用限制等非技术性要求。(系统分析员解决的问题)
在进行面向对象分析之前,系统分析员应该获得一份正确地表达用户需求对系统功能的要求、符合国家标准、行业标准及企业内部规范的需求文档。如果不能,应协商制定。
7.2.3 对象识别的客观性方法
对于一个给定的应用论域,一个合适的对象集合能够确保软件的可重用性、提高可扩性,并能借助于面向对象的开发模式,提高软件开发的质量和生产效率。因此,必须在科学、正确识别了对象集合的基础上才能发挥面向对象程序设计方法的优势。
在对象识别中最为关键的是正确地运用抽象原则。系统分析员应紧密围绕系统责任这个目标去对问题论域中的事物进行抽象和取舍,识别出反映系统特征的对象。用对象来映射问题论域中的事物。取舍的准则是问题论域中的事物及其特征是否与当前的目标有关。
具体讲,要做两方面的工作。①要舍去与系统责任无关的事物,②舍去与系统责任有关的事物中与系统责任无关的特征。 判断事物及其特征是否与系统责任有关的准则是:该事物是否为系统提供了一些有用的信息或需要系统为其保存和管理某些信息;该事物是否向系统提供了某些服务或需要系统描述它的某些行为。
为了尽可能识别出系统所需要的对象,在系统分析的过程中应采用“先松后紧”的原则。即首先找出各种可能有用的候选对象,尽量避免遗漏;然后对所发现的候选对象逐个进行严格的审查,进行取舍、调整与合并等工作,使系统中的对象和类尽可能地紧凑。
寻找各种可能有用的候选对象的主要策略是:从问题论域、系统边界和系统责任三个方面出发,考虑各种能启发自己发现对象的因素,找到可能有用的候选对象。具体来讲,在问题论域去发现对象的因素包括人员、组织、物品、设备、事件、表格、结构等。在系统边界方面,应该考虑的因素包括人员、设备和外部系统——交互方式所涉及的因素。对责任的分析是基于发现对象识别的遗漏的考虑,如发现所找的对象不能满足要求时需要增加对象。
在找到许多可能有用的候选对象之后,需要进行的工作是对它们进行逐个审查,分析它们是否是OOA模型真正需要的,从而筛选或精简及合并一些对象,甚至于将有一些对象推迟到OOD 阶段再进行考虑。在进行判断同时,也可以使系统分析人员认识对象的一些属性和服务,并将这些属性和服务填写相应的对象的类符号中。
精简对象的一些方法是:
①对于只有一个或少数几个属性的对象,应考虑是否可以将它们合并到引用它们的对象之中;
②而对于只有一个或少数几个服务的对象,则可以考虑将该对象合并到请求者对象中去。
③对于类类的属性或服务不适合该类的全部对象时,应该重新进行分类;
④对于属性及服务相同的类,则可进行合并;
⑤对于属性和服务相似的类,则可以考虑建立一般——特殊结构或整体——部分结构,利用类的继承及派生对这些类进行简化;
⑥在遇到对同一事物进行重复描述的类,应对某一类进行适当的改造而去除冗余的类。
对于候选对象中那些与具体的实现条件密切相关的对象,应推迟到OOD阶段进行考虑,以确保OOA模型可以独立于具体的实现环境而只与问题论域有关。
从识别对象到定义它们的类是一个从特殊个体上升到一般概念的抽象过程,需要为每一种对象定义一个类,并用一个符号进行表示,同时还应把类属性和服务填写到类符号中,以得到这些对象的类。
在面向对象软件设计中,发现对象的一个简单而有效的方法是利用语言信息分析(linguistic_based diagrams,LIA) 和三视图模型(3—view modeling,3VM) 的结合进行对象的识别,发现应用论域的初始空间。图7.4说明了将3VM和LIA应用于对象识别的过程。
三视图(3VM)利用了三种非常有效的传统系统分析工具:数据流图、实体——关系图以及状态——迁移图。
实体关系图(entity_relationship diagrams,ERD)是OOA的一个有力的工具。在实体——关系图中:实体很有可能就是以后要构造的对象,而实体的属性则可以表示成最终要由对象进行存储的数据;实体之间的关系有可能将建立“关联对象”,而所谓关系的“基数”(值的对应和“条件性”则有可能称为维持这些关系的服务。但其在应用时也存在问题:识别的实体可能与应用论域概念无关,且ERD对于那些不存储数据的对象显得无能为力。
常用的数据流模型有两种:上下文图和分层的数据流图,是识别对象的有力工具。上下文图可以确定一个全局的系统边界,它所识别的外部实体表示数据流的源端或目的端(候选对象);而上下文图中的数据流代表了该系统的输入和输出。因此任何一种对象集合都必须阐明这些上下文图中的数据流是如何被接收、处理及生成的。在适当的情况下,会产生分层的数据流图集合,即将待开发系统的功能分解成为一些基本单元,它们可被看作是一些详细说明或基本处理规格说明(primitive_process specificationS,PPSs),而这些PPSs最后必须对应于对象的方法或服务。
常用的有两种形式的状态——迁移模型:事件——响应模型和状态——适移模型,它们也用于对象识别的工具。事件——响应模型识别出系统必须进行识别的所发生的每一个事件以及系统必须做出的预期的响应事件。该模型的事件成分有助于识别一系列的识别事件的对象,而响应成分则有助于识别一系列发生事件的对象。在某些特殊的情况下,为系统建立一个或多个状态——迁移图将有助于识别对象,它除了能识别事件、识别对象和事件产生对象之外,还有助于识别保存状态信息的属性。
书P198~P199中的图7.5~图7.8是中英文双向电子字典系统(EDS)用于事例分析系统的3VM图。
1.Word Input
(单词输入)
A.修改词汇输入框内容
B.向搜索引擎发送搜索指令
2.Mouse Pick_up
(鼠标拾取)
A.在鼠标位置生成显示区域
B.向搜索引擎发送搜索指令
3.Search Successfully
(搜索成功)
A.向中英文词库发送调记录指令
B.向语音词库发送调记录指令
C.修改列表框内容
4.Search Failure
(搜索失败)
A.按词库中与被检索词最近的下
一个单词重新进行搜索
5.Word Library Retrieve
(中英文词库记录取得)
A.更新结果输出框内容或在取词
显示区域显示结果
6.Sound Library Retrieve
(语音词库记录取得)
A.发送语音播放指令
7.Mouse Move
(鼠标移动)
A.若存在显示区域,则清除显示
区域
8.Pick_up in ListBox
(在列表框中进行选择)
A.向搜索引擎发送搜索指令
图7.7 EDS的事件—响应模型
语言信息分析(LIA)是将某些语言规则应用到软件系统分析中的处理方法,它可以为识别对象提供大量的指导。LIA的目的是识别出应用论域的概念空间以及这些概念之间的关系。常用的LIA方法是短语频率分析(phrase frequency analysis,PFA)和矩阵分析(matrix analysis,MA)。这两种方法都需要建立一个资源库,该资源库中包括相关文档、模型、软件、人员以及包含应用论域或系统知识的其他资源。所有这些资源都包含一个文本库,而LIA技术可应用于该文本库。LIA技术通常只应用于资源库的某个子集,这取决于分析员想把什么样的视图用于应用论域或应用系统。
短语频率分析搜索选定的资源文本,以识别可以表示应用论域概念的术语。PFA清单的建立基本上是一个客观的过程,其中大多数表示出来的概念与待开发出来的应用系统无关。PFA的优点在于能广泛地识别应用论域的概念集合,并对它们进行评估,判定它们中哪些与待开发软件无关,并将其丢弃。将PFA清单转换为OOA/OOD工作表格将非常有用,它提供了一种系统的方法,可用于评审相当长的PFA清单并识别出OOA成分的初始集合。
矩阵分析(MA)是一种比PFA更复杂、实现起来更困难的技术。通常是在初始化对象识别出来以后再使用MA技术。MA分析的成果是一个二维MA表,该表的行和列是应用论域的概念,而这些概念通常可以产生所识别对象的初始集合。初始MA可以从资源中机械地构造出来,但分析员逐个元素地评审和讨论MA表,识别出应用论域的关系,还可能会发现新的,在初始的PFA中没有产生的对象。MA方法的主要优点是其系统性和条理性。
7.2.4 识别对象的内部特征
识别对象的内部特征包括定义对象的属性与服务这两个部分的工作。
问题论域中的事物的特征可以分为静态特征和动态特征。静态特征可以通过一组数据来表示,而动态特征则可以通过一系列操作来表达。
对象的属性是描述对象静态特征的数据项,而对象的服务则是描述对象动态特征(行为)的操作序列。对象的属性和服务描述了对象的内部细节,只有给出了对象的属性和服务,才能说对于该对象有了确切的认识和定义。
按照面向对象方法的封装原则,一个对象的属性和服务是紧密结合的,对象的属性只能由该对象的服务来进行访问,即确定对象状态的属性数据应该是private型或protected型的。而对象的服务可以分为内部服务和外部服务,与之相对应的是private型、protected型和public型。内部服务只供对象内部的其他服务使用,不能在外部进行调用;而外部服务则对外提供一个消息接口,通过这个接口接收对象外部的消息并为之提供服务。
对于对象的属性和服务,面向对象方法提供了专门的表示方法:对象的属性用在类符号中部填写的各属性的名字;而对象的服务则用在类符号的下部填写的各服务的名称表示。
7.2.4.1 定义对象的属性
由于面向对象方法具有对象重用的巨大优势,因此在定义对象的属性时可以借鉴以往OOA的成果,查看相同或相似的问题论域是否有已开发的OOA模型,尽可能利用其中同类对象的属性定义。然后研究当前问题论域和系统针对本系统应该设置的各类对象,按照问题论域的实际情况,以系统责任为目标进行正确的抽象,从而找出各类对象应有的属性。
可以从以下角度去确定对象应具有的属性:
(1) 按一般常识,该对象应具有的哪些属性。
(2) 在当前问题论域中,该对象应具有哪些属性。
(3) 根据系统责任的要求,该对象应具有哪些属性。
(4) 建立该对象是为了保存和管理哪些信息。
(5) 对象为了在服务中实现其功能,需要增设哪些属性。
(6) 是否需要增设属性来区别对象的不同状态。
(7) 用什么属性来表示对象的整体—部分联系和实例连接。
对于找到的对象属性,还应进行严格的审查和筛选,才能最终确定对象应具备的属性。在审查和筛选中,应考虑的问题有:
(1) 该属性是否体现了以系统责任为目标的抽象。
(2) 该属性是否描述了该对象本身的特征。
(3) 该属性是否破坏了对象特征的“原子性”。
(4) 该属性是否已通过类的继承而得到。
(5) 该属性是否可以从其他属性而得到。
在确定了对象属性之后,应对各属性命名加以区别。在工件的最后,应在类描述模板中给出每个属性的详细说明。该说明包括以下信息:
(1) 属性的解释。
(2) 属性的数据类型。
(3) 属性所体现的关系。
(4) 属性的实现要求和其他。
7.2.4.2 定义对象的服务
发现和定义对象和OOA的其他活动一样,可以借鉴以往同类系统的OOA成果,同时还应研究问题论域和系统责任以明确各个对象应该设立哪些服务以及如何定义这些服务。
在定义对象服务时,应注意以下问题:
(1)考虑系统责任,审查各项功能要求,并确定相应的对象和服务。
(2)考虑问题论域,确定设立哪些服务来摸拟哪些与系统责任无关的行为。
(3)分析对象的状态,确定实现对象状态转换的对象服务。
(4)追踪服务的执行路线,发现可能遗漏的服务。
在初步确定对象的服务之后,还必须对所确定的服务进行详细的审查,并最终确定所需的的对象服务。在对对象服务的检查中,应着重检查以下两点:
(1)检查每个服务是否真正有用。一个有用的服务或者直接提供某种系统责任所要求的功能,或者响应其他对象服务的请求而间接的完成这些功能的某些局部操作。否则是无用的,应该舍弃。
(2)检查一个服务是否只完成一项明确定义的、完整而单一的功能。如果一个服务中包括了多项可以独立定义的功能,则应将它分解为多个服务。反之,若发现把一个独立的功能分割到多个对象服务中去完成的情况,应加以合并,使一个服务对它的请求者体现一个完整的行为。
服务的命名应采用动词或动词加名词组成的动宾结构,服务名应尽可能准确地反应该服务的职能。
在定义服务的最后,还应在类描述模板中给出各服务的详细说明。对服务的详细说明中应包含以下一些主要内容:
(1)服务解释:解释该服务的作用及功能。
(2)消息协议:给出该服务的入口消息格式。
(3)消息发送:指出在该服务执行期间需要请求哪些别的对象服务。
(4)约束条件:该服务执行的前置、后置条件以及执行事件等需要说明的事项。
(5)服务流程图:对较复杂的服务,需要给出表明该服务执行流程的服务流程图。
在识别对象的内部特征的最后,应把每个对象的属性和服务都有填写到相应的类符号中去,构成类图的特征层。而对特征层的描述,则是在类描述摸板中对每个对象属性和服务的详细说明。
7.2.5 定义对象的外部特征
系统是由一系列的类和对象构成的,各个类和对象之间存在一定的关系,这些关系可以在OOA模型的关系层中得到体现。只有定义和描述了各个类和对象以及各对象之间的关系,才能构成一个完整的、有机的系统模型。
对象(以及它们的类)与外部的关系有如下四种:
(1)一般—特殊关系(继承关系):即对象之间的分类关系,用一般—特殊结构表示。
(2)整体—部分关系:即对象之间的组成关系,用整体—部分结构表示。
(3)静态连接关系:即通过对象属性所反映出来的联系,用实例连接来表示。
(4)动态连接关系:即对象行为之间的依赖关系,用消息连接表示。
表示上述关系的两种结构和两种连接将构成OOA模型的关系层。
7.2.5.1 定义一般—特殊结构
一般—特殊结构又称为分类结构,是由一组具有一般—特殊关系(继承关系)的类所组成的结构。一般用一般—特殊结构连接符来连接结构中的每个类来表示一般—特殊结构。其中,从圆弧引出的连接线连接到一般类,而从直线边分出的连接到每个特殊类。完整的一般—特殊结构应包括结构中的每个类。为了表示一般—特殊结构中的对象多态性,还引入了表示符“*”和“×”,前者表示对继承来的某个属性或服务给出新的定义,后者表示拒绝继承某个属性或服务。
为了发现一般—特殊结构,可以借鉴同类问题论域以往的OOA成果,发现可利用的系统成分,同时还应采用如下策略:
(1) 学习问题领域的分类学知识并加以利用,找出与之对应的一些一般—特殊结构。
(2) 按常识考虑事物的分类,从而发现其一般—特殊关系。
(3) 综合考察类的属性与服务,加以拆分和合并。
(4) 考虑领域范围内的复用,在更高水平上运用一般—特殊结构,提出一些可复用性更强的类构件。
在找到一系列候选的一般—特殊结构后,还应逐个对它们进行审查,从而舍去那些不合适的结构或对它们进行调整。进行审查的原则如下:
(1) 问题论域是否需要这样的分类。
(2) 系统责任是否需要这样的分类。
(3) 这种分类是否符合分类学的常识。
(4) 这种分类是否构成了继承关系。
一般—特殊结构把问题域中具有一般—特殊关系的事物组织在一起,使得OOA模型更加清晰地映射问题论域中的事物。但是也不能无节制地建立一般—特殊结构,否则增加了系统复杂性,加深了继承的层次,也增加了系统的理解难度和处理开销。因此,对结构中的每一对有继承关系的类,应权衡其得失,进行较好地协调。
7.2.5.2 定义整体—部分结构
整体—部分结构又称为组装结构,用于描述系统中各对象之间的组成关系。通过它可以了解哪些类的对象使用了其他类的对象作为其组成的一部分。
发现整体—部分结构的基本策略是从不同方式去考虑事物之间的组成情况。在定义整体—部分结构时,应考虑以下几个方面:
(1) 物理上的整体事物和它的组织部分。
(2) 组织机构和它的下级组织及部分。
(3) 团体组织和成员。
(4) 一种事物在空间上包含其他事物。
(5) 抽象事物的整体和部分关系。
(6) 具体事物和它的某个抽象方面。
在发现了一系列候选整体—部分结构后,需要对其进行严格的审查和筛选,以确定最终采用的整体—部分结构。在审查时需要考虑以下几个方面:
(1) 该结构是否属于问题论域。
(2) 该结构是否是系统责任所需要的。
(3) 部分对象是否有一个以上的属性。
(4) 是否有明显的整体—部分关系。
在定义整体—部分结构时可能会发现一些新的对象类,或者从整体对象的定义中分割出一些部分对象的类定义,这时应把它们加入到对象层中,并给出它们的详细说明。
定义实例连接
实例连接用以表达对象之间的静态联系,即通过对象属性来表示一个对象对另一个对象的依赖关系(二元关系)。在OOA模型中,通常在具有实例连接的类之间画一条连接线把它们连接起来,用来表示两类对象之间不带属性的实例连接,在连接线旁边注明连接名(也可附加必要的详细说明),并在连接线的两端用数字标明其连接的一对一、一对多及多对多的多重性。实例连接一般可以用对象指针或对象标识来实现,即在被连接的两个类中选择其中的一个,在它的对象中设立一个指针类型的属性,用以指向另一个类中与它有连接关系的对象实例。
为了建立实例连接,应该进行如下的分析活动:
(1) 分析对象之间的静态联系。
(2) 分析实例连接的属性与操作。
(3) 分析实例连接的多重性。
(4) 分析多元关联和多对多实例连接等异常情况处理。
如在建立实例连接的过程中增加了新的对象类,应把这些新增的类补充到类图的对象层中,并建立它们的类描述模板。
建立消息连接
在软件系统中,消息指的是一个软件成分向其他软件成分发出的控制信息或数据信息。一个消息应具有发送者和接收者共同约定的语法和语义。接收者在收到消息后,将按照该消息的要求做出某种响应。在OOA方法中,按严格封装的要求,消息是对象之间在行为上唯一的联系方式。对象以外的成分不能直接地存取该对象的属性,只能向这个对象发送消息,由该对象的一个服务对接收到的消息做出响应,并完成发送者所要求的动作。
在OOA模型中,带箭头的有向线段表示消息连接,并从消息的发送者指向消息的接收者。
在OOA模型中建立消息连接包括建立每个控制线程内部的消息连接和建立各个控制线程之间的消息连接,以下将分别进行介绍。
1,建立控制线程内部的消息连接其基本策略是“服务模拟”和“执行路线追踪”,具体做法是从类图中每个主动对象的主动服务开始,做如下检查工作:
(1) 人为地模拟当前对象服务的执行,检查对象为了完成当前的工作,是否需要对其他对象要求新的请求,如有新的请求则是发现了一种新的消息。
(2) 分析该消息的发送者与接收者在执行时是否输入同一个控制线程。
(3) 在当前服务的详细说明中指出由它发出的每一种消息的接收者,并从当前服务所在的类向所有接收消息的对象类画出消息连接。
(4)沿着控制线程内部的每一种消息追逞到接收该消息的对象服务。
重复以上工作,按宽度优先或深度优先的原则,进行穷举式搜索,直到将已发现的全部消息都经历一遍。同时对全系统的对象类做一次检查,确定每个类的每个服务是否都曾经到达并模拟执行过,如果某个服务从未到达过,则有两种可能:一是这个服务是多余的,另一个是遗漏了向这个服务发出的消息。对于遗漏的消息要进行补充,对确实无用的服务要进行删除。
2、建立控制线程之间的消息连接仅仅在并发系统的分析中需要建立控制线程之间的消息连接,且它是在建立了控制线程内部的消息连接之后进行的。当然在进行对象服务模拟和执行路线追踪时,也可能会发现一些控制线程之间的消息。为了全面找出控制线程之间的消息连接,还需要进行更全面的分析。
在建立控制线程之间的消息连接时,系统分析员可以以已经找出的源于主动对象的控制线程作为并发执行单位,对整个系统的动态执行情况进行全局的观察,从而发现这些控制线程之间需要哪些消息。对每个控制线程,主要应该考虑以下问题:
(1)线程在执行时,是否需要请求其他控制线程中的对象为它提供某种服务?这种请求由哪个对象发出?由哪个对象中的服务进行处理?
(2)线程在执行时是否要向其他控制线程中的对象提供或索取某些数据?
(3)线程在执行时是否将产生某些对其他控制线程的执行有影响的事件?
(4)各个控制线程的并发执行,是否需要传递一些同步控制信号?
(5)一个控制线程将在何种条件下终止执行?在它终止之后将在何种条件下由其他控制台线程唤醒?由什么办法唤醒?
此外还要分析消息是否同步,发送者是否等待消息的处理结果等等,这些都应在发送者和接收者的类描述模板中针对有关的服务进行详细说明。在相应的类符号之间画出用虚箭头表示的消息连接符。
信息建模的规范化过程
所谓信息建模是指从现实世界中捕捉并抽象出应用论域的基本结构的过程。它是OOA的核心。在OOA中,信息建模的基本任务是建立现实世界中事物(对象)的抽象表示,即使用基本模块构造出抽象化的事物来。这被认为是软件工程中的一个规范化的过程。
在信息建模的过程中,所建立的OOA模型描述了表示某个特定应用论域中的对象以及各种各样的结构关系和通信关系。OOA模型有两个主要用途:
(1) 它建立各种对象,分别表示软件系统主要的组织结构以及现实世界强加给软件系统的各种规则和约束条件,形式化现实世界的视图。
(2) 它给定一组对象,并规定了它们如何协同才能完成软件系统所指定的工作。
在信息建模的规范化过程中,OOA模型被划分为5个层次或5个视图,如图7.10所示。这种层次结构允许从不同的角度来看待OOA模型,同时也便于处理比较大的OOA模型。