“数据流图的基本构成、数据字典、加工逻辑
(1)补充数据流图的 缺失部分,包括补充数据流、补充外部实体、补充数据存储以及处理过程(四个部分)
(2)数据流图的改错,包括修正数据流名称、数据流的起点与终点、删除多余数据流。
数据流图:
1、4个部分组成(实体,存储表,数据流,过程处理),可能要你建模的时候补充。
2、数据流改错( 名称不对,起点终点不对,多余的,缺少的 )
数据流图(Data Flow Diagram):简称DFD,它从数据传递和加工角度 ,以图形方式来表达系统的逻辑功能、数据在系统内部的逻辑流向和逻辑变换过程 ,是结构化系统分析方法 的主要表达工具。
数据流图主要由实体、数据存储、处理过程和数据流四部分 组成。在顶层数据流图 中,将系统描述成一个处理过程 ,而其它的是与该处理过程相关的输入输出流 ,因此顶层数据流图描述了系统的输入与输出 。
分层数据流图(DFD)
从图11-1可以看出,越庞大的系统,数据流图越复杂。以至于一张图根本无法清楚的表达系统内容 ,所以需要对图进行分层,逐层精化 。目前使用的数据流图都是分层次 的,这也就是为什么平时也把数据流图称为“分层数据流图”的原因。分层数据流图很好的传承了结构化思想——“自顶至下,逐步精化 ”。将图分成了若干个层次,首先绘制针对系统整体的顶层图,以说明系统与外界的交互, 再将图层层细化。具体过程为:
(1)画系统的输入和输出:把整个软件系统看做一个大加工 ,确定与外部实体之间的输入和输出数据流,这个结果也称为顶层图 。
如图11-2所示,数据管理中间件是我们要开发的系统 ,但顶层图将该系统看成了一个大加工,这种图能很好的体现出系统与外部实体之间 的交互关系。
(2)画系统的内部:将顶层图中的加工分解成若干个加工 ,并用数据流连接这些加工 。这张图称为0层图 。而从一个加工画出一张数据流图的过程就是对该加工的分解过程。如图11-1所示它便是图11-2的0层图, 在该图中,展示出数据管理中间件拥有一系列的加工 :用户验证、用户管理、操作管理、权限管理、格式检查、权限验证、连接管理,以及这些加工之间的关系 。从这张图,可以大致看出原始数据是经历了哪些步骤,产生了目标数据。但这还不够详细,例如我们需要了解“格式检查”是如何进行格式检查的,从该图仍无法得到答案。此时,可以进一步细化“格式检查”的内部结构,这便是下一步“画加工的内部”需要做的事情。
(3)画加工的内部:把每个加工看做一个小系统,以画0层图的方式画出每个加工的DFD子图 (对于较细的加工,可以不进行分解)。
数据字典
DFD描述了系统的分解,即系统由哪几部分组成 ,各部分之间的联系等,但是,对于数据的详细内容却无法在DFD中得到反映 。例如,图11-2中的数据流“用户信息”包括哪些内容,在DFD中就无法具体、准确地描述。数据字典是在DFD的基础上,对DFD中出现的所有命名元素都加以定义 ,使得每个图形元素的名字都有一个确切的解释。DFD和数据字典等工具相配合 ,就可以从图形和文字两个方面对系统的逻辑模型进行完整的描述。
数据平衡原则
数据平衡原则有两个层面的意思,一方面是分层数据流图之间需要平衡 ,另一方面是每张数据流图的数据需要平衡 。
(1)分层数据流图的数据平衡原则
分层的流程图是由粗至精、逐步细化 地描述系统信息的。上层图中描述的是粗略涉及全体的信息 ,而下层图中则详细描述上层图中具体某一个部分的内容 。因此,上层图不需要描述下层图中所描述的详细信息,而下层图的输入与输出应与上层图保持一致 ,也就是父图和子图之间的数据流必须保持一致。比如说在父图中某加工有两个输入数据流和一个输出数据流,那么在该加工的子图中的输入/输出数据流必须在数目上和内容上与父图保持一致。
此外值得注意的是:保持一致并非指输入输出流的数量与名称完全一样。而是下层数据流图的所有输出数据流必须是上层数据流图中相应加工产生的输出数据流 。如果上层数据流底部某加工的一个输入(输出)数据流对应于下层数据流图中若干个输入(输出)数据流,而且下层数据流图中这些数据流的成分之和正好等于上层数据流底部的这个数据流,那么它仍算是平衡的。
(2)每张数据流图的数据平衡原则
加工的输入数据流和输出数据流要平衡,即保证加工的输出数据流都有其对应的输入数据流与输出数据流。以下属于打破了数据平衡原则,会产生错误的情况。若一个加工只有输入数据流而无输出数据流,则称为黑洞 。若一个加工只有输出数据流而无输入数据流,则称为奇迹 。若一个加工的输入数据流无法通过加工产生输出流,则称为灰洞。此外需要注意的是:一个数据流图中,不允许数据流同名 。
答题技巧
通过对前面内容的学习,我们可以发现,数据流图涉及的相关内容并不多。只有一些简单的概念与原则,但该知识点的重要度却非常高。每次考试都有该类试题,考查15分以上(如果上午题考到数据流图知识,则考查分值超过15分),而且考查的形式也非常固定,所以这个种题是拿分的题,要掌握其解答技巧,避免在此类问题上丢分。技巧主要有两点:详细分析试题说明以及充分利用数据平衡原则 。
(1)详细分析试题说明
在考试中,要看清楚试题再作答,这其实是大家都清楚的规则,但真正做得很好的并不多。有很多考生觉得考试时间有限,是采取的“粗略看题,凭空作答”的方式,这样做很危险,费时且没有成效。这种情况要避免。
试题说明在解答数据流图题中,表现得尤为重要。这是有依据的,因为数据流图本身是需求分析阶段用来建模的工具 。用数据流图建模,不能凭空想像。
绘制数据流图需要依据用户需求 以及用户操作的一些流程说明,而在试题中,试题说明恰好就是这些素材。这些素材是解题的关键 。我们在此需要逐字逐句的进行分析与推敲。
例如,有一个关于中间件系统的数据流图题 。试题说明中有“数据管理员 可通过中间件进行用户管理、操作管理和权限管理 。用户管理维护用户信息,用户信息(用户名、密码)存储在用户表 中;操作管理维护数据实体的标准操作及其所属的后端数据库信息,标准操作和后端数据库信息存放在操作表 中;权限管理维护权限表 ,该表存储用户可执行的操作信息。”,
从这段话,我们可以得到的信息有:
数据管理员是一个外部实体;
中间件中有“用户管理”、“操作管理”、“权限管理”这些加工 ;
中间件中有“用户表”这个数据存储,且该存储与“用户管理”相关;
后端数据库是一个外部实体;
中间件中有“操作表”这个数据存储,且该存储与“操作管理”相关;
中间件中有“权限表”这个数据存储,且该存储与“权限管理”相关。
如果进一步结合试题已给出的图,能得到更多的信息,所以在解题时,要反复分析试题说明中的文字,这是解题的关键。
(2)利用数据平衡原则
数据平衡原则在前面已有说明。在此主要强调它在解题中的使用。在解答“补充数据流”或是“数据流查错” 这些类型的题时。数据平衡原则起到了重要作用,我们通常可以用外部实体为主线 ,在不同层次的图上分析与该外部实体相关的输入输出流 ,如果存在不匹配的情况,则说明图中该处有误。
例如,在某系统中,对于实体E,在顶层图中相关数据流情况如图11-4(a)所示,而在0层图中相关数据流如图11-4(b)所示。则我们可以清楚的看到0层图存在数据流缺失 的情况。
数据库设计:
1、(概念设计)ER模型包含了实体,属性 和 联系 三个部分。可能补充弱实体或缺失的联系(直接看题目补)
2、可能会补充关系模式,E-R图向关系模式的转换属于数据库的逻辑设计阶段
(1)设计关系模式:掌握给定一个实际的应用问题如何设计E-R模型,如何将E-R模型转换成关系模式,确定联系类型、主键、候选键、外键,判断关系模式规范化的程度。
(2)数据库语言(SQL):掌握给定一个实际的应用问题如何用SQL进行数据定义(创建表、视图)、完整性定义及权限定义。
(3)数据库访问:掌握常用数据库的访问方法。
1. 数据库设计的阶段划分
前面的章节曾提到软件的开发分了多个阶段,而软件开发的本身包括了流程方面的设计与数据方面的设计 。数据库设计正是数据层面的规划 ,所以数据库设计也有阶段的划分 ,它与软件开发的阶段是吻合的。数据库设计包括需求分析、概念结构设计、逻辑结构设计和数据库物理设计四个阶段 。如图12-1所示。
这四个阶段的主要工作与产出物总结起来,如表12-1所示。
2. ER模型高级知识
关于ER模型的相关内容,第5章已有相关说明,应对上午考试的相关问题那些知识已经足够用了,但下午案例分析题难度将超过该水平,因为会涉及ER模型的高级知识。ER模型的高级知识包括:弱实体、特殊化、概括、聚集,考试中要求掌握弱实体与特殊化 。
(1)弱实体
弱实体是一类特殊的实体,这种实体需要依赖于另一个实体,若另一个实体不存在了,它也随之消失。 相对而言,弱实体所依赖的那个实体称为强实体。
例如:订单实体与订单明细之间便存在这样的关系,订单实体是强实体,而订单明细为弱实体,若订单实体不存在了,订单明细也就没有存在的必要性了。强实体与弱实体之间的关系表达,与常规的ER模型略有差异,如图12-2所示。
(2)特殊化
在数据库的设计过程中,有时我们会发现,一个实体可以按照某些特征分为几个子实体 ,这其实是从普遍到特殊的一个过程,这被称为“特殊化”。仅从概念理解,会非常抽象,下面看一个例子。
例如:学生这个实体,它就包含了多个子集:大专生、本科生、硕士生、博士生。这便是特殊化。其示意图如图12-3所示。
UML建模:
根据考试大纲,本章要求考生掌握以下几个方面的知识点。
(1)UML的基本概念与作用
(2)用例图的表示与应用
(3)类图与对象图的表示与应用
(4)序列图的表示与应用
(5)活动图的表示与应用
(6)通信图的表示与应用
(7)组件图的表示与应用
(8)部署图的表示与应用
(9)状态图的表示与应用
UML是一种与开发方法无关的建模语言 ,其应用十分广泛。本节将从它的起源、概念、组成部分等方面展开论述,最后将对各种常用的UML图进行详细解读。
UML的起源
前面的章节已经提到过软件开发方法有三种:结构化方法、面向对象方法、原型法 。其中能应用于软件全生命周期 的是:结构化方法与面向对象 方法,原型法一般只用于需求分析阶段 。
面向对象方法是在结构化设计方法出现很多问题 的情况下应运而生的。从结构化设计的方中,我们不难发现,结构化设计方法求解问题的基本策略是从功能的角度审视问题域 。它将应用程序看成实现某些特定任务的功能模块 ,其中子过程是实现某项具体操作的底层功能模块 。在每个功能模块中,用数据结构描述待处理数据的组织形式 ,用算法描述具体的操作过程 。面对日趋复杂的应用系统,这种开发思路在以下几个方面逐渐暴露了一些弱点:审视问题域的视角、抽象级别、封装体、可重用性 。这样就催生了一批面向对象方法,形成百家争鸣的局面,后来由Booch方法、OOSE、OMT三大主流OOA技术的创始人通过融合与整理,形成了新的标准——UML(统一建模语言) 。目前,UML已经纳为国际标准,是软件系统建模的主要规范之一。
UML的组成
关于UML的组成,有很多人存在误解,误认为:“UML由一系列的UML图组成”,这种观点是错误的。UML由构造块、公共机制、规则三个部分组成 ,如图13-1所示。
(1)构造块
构造块 犹如建房子时的砖瓦,包括事物构造块、关系和图 。
事物构造块 :包括结构构造块 (类、接口、协作、用例、活动类、构件、节点等)、行为构造块 (交互、状态机)、分组构造块 (包)、注释构造块。
关系 :包括关联关系 (包括表示整体-部分关系的聚合、组合关系)、依赖关系 、泛化关系 (表示一般/特列关系)、实现关系 。
图 :在UML 2.x中包括14种不同的图 ,分为表示系统静态结构的静态模型 (包括对象图、类图、构件图、部署图、复合结构图、包图、制品图);以及表示系统动态结构的动态模型 (包括用例图、顺序图、协作图、状态图、活动图、定时图、交互概观图)。
(2)规则
规则是支配基本构造块如何放在一起的规则 。
这些规则可以用于:
命名:也就是为事物、关系和图起名字;从语义的有效性而言,只要求是由字符、数字、下划线组成的唯一串;另外也要求是唯一的。
范围:使名字具有特定含义的语境。
可见性:用来表示编程语言中的public、private、protected等修饰符。
完整性:事物如何正确、一致地相互联系。
执行:运行或模拟动态模型的含义是什么。
UML对系统体系结构的定义 是系统的组织结构,包括系统分解的组成部分 、它们的关联性、交互、机制和指导原则,这些提供系统设计的信息。
而具体来说,就是指5个系统视图,分别是逻辑视图、进程视图、实现视图、部署视图和用例视图 。
逻辑视图:以问题域的语汇组成的类和对象集合 。
进程视图:可执行线程和进程 作为活动类的建模,它是逻辑视图的一次执行实例,描绘了所设计的并发与同步结构。
实现视图:对组成基于系统的物理代码的文件和构件 进行建模。
部署视图:把构件部署到一组物理的、可计算的节点上 ,表示软件到硬件的映射及分布结构。
用例视图:最基本的需求分析模型。
(3)公共机制
公共机制是指达到特定目标的公共UML方法 ,主要包括规格说明、修饰、公共分类和扩展机制四种 。
规格说明:规格说明是元素语义的文本描述 ,它是模型真正的“肉”。
修饰:UML为每一个模型元素设置了一个简单的记号 ,还可以通过修饰来表达更多的信息。
公共分类:包括类元与实体 (类元表示概念,而实体表示具体的实体)、接口和实现 (接口用来定义契约,而实现就是具体的内容)两组公共分类。
扩展机制:包括约束(添加新规则来扩展元素的语义)、构造型(用于定义新的UML建模元素)、标记值(添加新的特殊信息来扩展模型元素的规格说明)。
首先值得强调的是:用例图在所有UML图中,重要程度是最高的 。几乎在每次考试中都会考用例图,所以本节将对用例图进行详细论述。
在了解用例图的基本情况前,我们有必要先理解什么是用例 。Ivar Jacobson是这样描述的:“用例实例是在系统中执行的一系列动作,这些动作将生成特定参与者可见的价值结果 。一个用例定义一组用例实例 。”
首先,从定义中得知用例是由一组用例实例组成的 ,用例实例也就是常说的“使用场景” ,就是用户使用系统的一个实际的、特定的场景。其次,我们可以知道,用例应该给参与者带来可见的价值 ,这一点很关键。最后,我们得知,用例是在系统中的。通俗一点来理解,用例可以看成系统的功能,例如在结构化方法中,有登录这个功能,在使用UML建模时,“登录”将被构造为一个用例 。
用例图的概念:
用例图(也可称用例建模)描述的是外部执行者(Actor)所理解的系统功能 。用例图用于需求分析阶段 ,它的建立是系统开发者和用户反复讨论的结果 ,表明了开发者和用户对需求规格达成的共识。
在UML中,用例表示为一个椭圆。图13-2显示了一个图书管理系统的用例图。其中,“新增书籍信息”、“查询书籍信息”、“修改书籍信息”“登记外借情况”、“查询外借情况”、“统计金额与册数”等都是用例的实例。
用例分析技术 为软件需求规格化提供了一个基本的元素 ,而且该元素是可验证、可度量的。
用例可以作为项目计划、进度控制、测试等环节的基础。而且用例还可以使开发团队与客户之间的交流更加顺畅。
用例图的建立:
用例图的建立通常要经历三个阶段:识别参与者、合并需求获得用例、细化用例描述 。
(1)识别参与者
参与者(Actor)是同系统交互的所有事物 ,它是指代表某一种特定功能的角色 ,因此参与者都是虚拟的概念。在UML中,用一个小人表参与者。该角色不仅可以由人承担,还可以是其他系统、硬件设备、甚至是时钟 。
其他系统:当你的系统需要与其他系统交互时,如在开发ATM柜员机系统时,银行后台系统就是一个参与者。
硬件设备:如果你的系统需要与硬件设备交互时,如在开发IC卡门禁系统时,IC卡读写器就是一个参与者。
时钟:当你的系统需要定时触发时,时钟就是一个参与者,如在开发Foxmail这样的电子邮件应用软件中的“定时自动接收”功能时,就需要引入时钟作为参与者。
要注意的是,参与者一定在系统之外,不是系统的一部分。通常可以通过以下问题来整理思路:谁使用这个系统?谁安装这个系统?谁启动这个系统?谁维护这个系统?谁关闭这个系统?哪些其他的系统使用这个系统?谁从这个系统获取信息?谁为这个系统提供信息?是否有事情自动在预计的时间发生?
(2)合并需求获得用例
用例是对系统行为的动态描述 ,它可以促进设计人员、开发人员与用户的沟通,理解正确的需求,还可以划分系统与外部实体的界限,是系统设计的起点。
在识别出参与者之后,你可以使用下列问题帮助你识别用例:每个参与者的任务是什么?有参与者将要创建、存储、修改、删除或读取系统中的信息吗? 什么用例会创建、存储、修改、删除或读取这个信息吗?参与者需要通知系统外部的突然变化吗?需要通知参与者系统中正在发生的事情吗?什么用例将支持和维护系统?所有的功能需求都对应到用例中了吗?系统需要何种输入输出?输入从何处来?输出到何处?当前运行系统的主要问题是什么?通常情况下,我们将在参与者都找到之后通过合并需求来获得用例。也就是仔细地检查参与者,为每一个参与者确定用例。而其中的依据主要可以来源于已经获取得到的“特征表”。将特征分配给相应的参与者:首先,要将这些捕获到的特征,分配给与其相关的参与者,以便’可以针对每一个参与者进行工作,而无遗漏。
进行合并操作 :在合并之前,我们首先还要明确为什么要合并,知道了合并的目的,也就会让我们选择正确的合并操作。一个用例就是一个对参与者来说可见的价值结果,因此合并的根据就是使得其能够组合成为一个可见的价值结果 。合并后,将产生用例,而用例的命名应该注意采用“动词(短语)+名词(短语)”的形式 ,而且最好能够对其进行编号,这也是实现跟踪管理的重要技巧,通过编号可以将用户的需求落实到特定的用例中去。绘制成用例图:最后我们就将识别到的参与者,以及合并生成的用例通过用例图(的形式整理出来。在此,经常需要使用包含和扩展关系来描述用例之间的关系,该内容在后面会详细叙述。
(3)细化用例描述
经历了前两步,用例图已经完成,大家或许认为用例建模已“大功告成”,但事实并非如此。
仅有用例图是不够的,因为这个图只能勾勒出一个大致的系统功能轮阔,系统很多细节信息都没有明确地表示出来。所以对于每个用例而言,我们还需要编写它的事件流。
就像类对应于对象一样,一个用例的实例就是一个使用场景 ,用例就是对使用场景进行抽象的总结,形成一组事件流。整个事件流的描述主线如图13-3所示。
前置条件:指在用例启动时,参与者(Actor)与系统应置于什么状态 ,这个状态应该是系统能够检测到的、可观测的;
后置条件:用例结束时,系统应置于什么状态 ,这个状态也应该是系统能够检测得到的、可观测的;
基本事件流:基本事件流是对用例中常规、预期路径的描述 ,也被称为Happy day场景,这时大部分时间所遇到的场景;它将体现系统的核心价值;
扩展事件流:主要是对一些异常情况、选择分支进行描述 。进行细化用例描述时,通常有两个步骤,首先将事件流的基本框架完成(类似于写书时,先写目录)。然后再对每个阶段要完成的具体工作描述出来。以图13-2所述的图书管理系统为例,若要完成“新增书籍信息”用例的事件流,可以先完成基本框架,结果如下所示。
包含、扩展与泛化
用例图中常见的关系有:包含、扩展与泛化 ,其中包含与扩展是用例图中特有的关系 ,而泛化关系不仅用于用例图,同时也适用于其它图,如类图。
用例之间的包含和扩展关系是分解和组织用例的有效工具 ,表面上看它们有许多相似之处,因此很多初学者经常容易混淆。下面将详细介绍这些关系的特点以及区别。
(1)包含关系
当可以从两个或两个以上的用例中提取公共行为时 ,应该使用包含关系来表示它们。其中这个提取出来的公共用例称为抽象用例 ,而把原始用例称为基本用例或基础用例。例如,图13-2中的**“登记外借信息”和“查询外借信息”** 两个用例都需要登录 ,为此,可以定义一个抽象用例“用户登录” 。用例“登记外借信息”和“查询外借信息”与用例“用户登录”之间的关系就是包含关系,如图13-4所示。其中“<>”是包含关系的构造型,箭头指向抽象用例。
当多个用例需要使用同一段事件流时,抽象成为公共用例,可以避免在多个用例中重复地描述这段事件流 ,也可以防止这段事件流在不同用例中的描述出现不一致。当需要修改这段公共的需求时,也只要修改一个用例,避免同时修改多个用例而产生的不一致性和重复性工作。另外,当某个用例的事件流过于复杂时,为了简化用例的描述,也可以将某一段事件流抽象成为一个被包含的用例 。
(2)扩展关系。如果一个用例明显地混合了两种或两种以上的不同场景 ,即根据情况可能发生多种分支,则可以将这个用例分为一个基本用例和一个或多个扩展用例 ,这样使描述可能更加清晰。例如,图13-2中的图书管理员进行“查询书箱信息”操作时,如果发现书箱信息有误,他可以使用**“修改书箱信息”用例来完成错误的修改** 。所以用例“查询书籍信息”和“修改书籍信息”之间的关系就是扩展关系,如图13-5所示。其中“<>”是扩展关系的构造型,箭头指向基本用例。
(3)泛化关系。当多个用例共同拥有一种类似的结构和行为的时候 ,可以将它们的共性抽象成为父用例 ,其他的用例作为泛化关系中的子用例。在用例的泛化关系中,子用例是父用例的一种特殊形式,子用例继承了父用例所有的结构、行为和关系。例如,图书管理系统中,用户注册时有多种方式,可以是“现场注册”,也可以是“网上注册” 。所以“用户注册”用例就是“现场注册”用例和“网上注册”用例的泛化,如图13-6所示。其中三角箭头指向父用例。
从UML事物关系的本质上来看,包含关系和扩展关系都属于依赖关系 。对包含关系而言**,抽象用例中的事件流是一定插入到基本用例中去的** ,并且插入点只有一个。扩展用例的事件流往往可以抽象为基本用例的备选事件流,在扩展关系中,可以根据一定的条件来决定是否将扩展用例的事件流插入到基本用例的事件流中,并且插入点可以有多个。在实际应用中,很少使用泛化关系,子用例的特殊行为都可以作为父用例中的备选事件流而存在。在实际工作中,要谨慎选用这些关系。从上面的介绍可以看出,包含、扩展和泛化关系都会增加用例的个数,从而增加用例模型的复杂度。另外,一般都是在用例模型完成之后才对它进行调整,在用例模型建立之初不必急于抽象用例之间的关系。
在面向对象建模技术中,我们将客观世界的实体映射为对象,并归纳成类。类(Class)、对象(Object)和它们之间的关联是面向对象技术中最基本的元素。对于一个想要描述的系统,其类模型和对象模型揭示了系统的结构。在UML中,类和对象模型分别由类图和对象图表示 。类图技术是OO方法的核心。
下面我们来总结一下类模型中的常见考点 。
确定类之间的关系:
在建立抽象模型时,我们会发现很少有类会单独存在,大多数都将会以某种方式彼此协作,因此我们还需要描述这些类之间的关系。关系是事物间的连接,在面向对象建模中,有4种很重要的关系。
依赖关系:有两个元素X、Y,如果修改元素X的定义可能会引起对另一个元素Y的定义的修改,则称元素Y依赖(Dependency)于元素X。在UML中,使用带箭头的虚线表示依赖关系,如图13-7所示。
在类中,依赖由各种原因引起,例如:一个类向另一个类发消息;一个类是另一个类的数据成员;一个类是另一个类的某个操作参数。如果一个类的接口改变,它发出的任何消息可能不再合法。依赖关系是一种很泛的关系,很多关系都属于依赖的范畴,将依赖关系进一步细化可得到表13-2。
泛化关系
泛化关系在用例图部分已经提及,该关系的应用范围较广,不仅可以用在用例图中,还可以在类图,对象图中使用。类图中的泛化关系描述了一般事物与该事物中的特殊种类之间的关系,也就是父类与子类之间的关系。继承关系是泛化关系的反关系,也就是说子类是从父类继承的,而父类则是子类的泛化。在UML中,使用带空心箭头的实线表示泛化关系,箭头指向父类,如图13-8所示。
在UML中,对泛化关系有3个要求。
1、子类应与父类完全一致,父类所具有的关联、属性和操作,子元素都应具有。
2、子类中除了与父类一致的信息外,还包括额外的信息。
3、可以使用父类实例的地方,也可以使用子类实例。
例如,我们称“自行车”和“小轿车”从“交通工具”继承,而“交通工具”是“自行车”和“小轿车”的泛化,如图13-9所示。
关联关系: **
关联(Association)表示两个类之间存在某种语义上的联系** 。例如,一个人为一家公司工作,一家公司有许多办公室。我们就认为人和公司、公司和办公室之间存在某种语义上的联系。
关联关系提供了通信的路径 ,它是所有关系中最通用、语义最弱的。在UML中,使用一条实线来表示关联关系 。而在关联关系中,有两种比较特殊的关系:聚合和组合 。
聚合关系 :聚合(Aggregation)是一种特殊形式的关联。聚合表示类之间的关系是整体与部分的关系 。聚合关系的含义是“聚”在一起的意义,也就是表示**“部分”可以独立于“整体”而存在** 。在UML模型中,使用一个带空心菱形的实线表示,空心菱形指向的是代表“整体”的类,如图13-10所示。
组合关系 :如果发现**“部分”类的存在,是完全依赖于“整体”类的** ,那么就应该使用“组合”关系来描述。在UML模型中,组合关系是使用带有实心菱形的实线表示,实心菱形指向的是代表“整体”的类。
那么到底聚合与组合的区别 在什么地方呢?许多书籍虽然举过很多例子,但是都忽略了,这种例子是必须依赖于“应用场景” 的。也就是要根据应用场景来判断部分类和整体类之间的关系。例如:“电脑”是一个整体类,而“主板”、“CPU”……则是相对于它的部分类。那么它们之间应该整体类还是部分类呢?如果你是在固定资产管理系统中,可能适合的就是“组合”,甚至只是“电脑”类的属性;而如果对于在线DIY的系统,那么显然应该采用“聚合”关系。对于组合而言,最易于理解的例子是“订单”与“订单项”之间的关系,如果订单不存在,显然订单项也就没有意义了,因此必然是组合关系。
原则:判断是聚合还是组合关系,关键在于要放到具体的应用场景中讨论。
实例分析
对于上面的例子中,很明显可以发现“计算机类书籍(ItBook)”、“非计算机类书籍(OtherBook)”与“书籍(Book)”之间是继承关系 。而**“书籍列表(BookList)”则是由多个“书籍”组成的** ,“借阅记录列表(BorrowList)”是由多条“借阅记录(BorrowRecord)” 组成而成的。这种组成关系适用于组合还是聚合关系 呢?显然,由于在本系统中“书籍”是可以独立于“书籍列表”存在的 ,“借阅记录”也是可以独立于“借阅记录列表”而存在的 ,因此使用聚合更合适一些 。另外,我还可以发现**“借阅记录”是与“书籍”关联** 的,离开“书籍”,“借阅记录”将失去意义。为了反映和记录这些类之间的关联关系,就可以使用UML中的类图将其记录下来,如图13-12所示。
多重性关系: **
重复度(Multiplicity)又称多重性 ,多重性表示为一个整数范围n…m,整数n定义所连接的最少对象的数目,而m则为最多对象数(当不知道确切的最大数时,最大数用号表示)。最常见的多重性有:0…1;0…(也可以表示为0…n);1…1;1…(也可以表示为1…n);(也可以表示为n)。
多重性是用来说明关联的两个类之间的数量关系** ,例如:
书与借书记录之间的关系,就应该是1对0…1的关系 ,也就是一本书可以有0个或1个借书记录。经理与员工之间的关系,则应为1对0…*的关系,也就是一个经理可以领导0个或多个员工。学生与选修课程之间的关系,就可以表示为0…对1…的关系,也就是一个学生可以选择1门或多门课程,而一门课程有0个或多个学生选修。在解答这类题目时,最关键的是要根据题意来理解它们之间的多重性关系,而不是从概念上,因为多重性是描述类之间的关联的,而类则是对现实对象的抽象。下面的图13-13就是在图13-12所示类图的基础上添加多重性信息的结果。
为类添加职责: **
当我们找到了反映问题域本质的主要概念类 ,而且理清了它们之间的协作关系之后,我们就可以为这些类添加其相应的职责。
什么是类的职责 呢?它包括两方面的内容:一是类所维护的知识;二是类能够执行的行为。 相信大家从上面的两句中,马上会想到类的成员变量(也称为属性)和成员方法 吧!是的,成员变量就是其所维护的知识,成员方法就是其能够执行的行为。
属性是用来描述一类对象的特性的值,它通常是名词或名词短语,因此也常使用名词动词法进行分析,先从备选类中选出候选类,然后再从被淘汰的备选类中进行选择。
方法则是该对象能够完成的行为与功能,它通常表现为动词或动词短语。对于我们前面分析的那个例子而言,可以继续根据需求描述的内容,以及与客户的简单沟通将主要类的主要成员变量和成员方法标识出来,以便更好的理解问题域。
书籍类:从需求描述中,我们已经找到了描述书籍的几个关键成员变量,即书名、类别、作者、出版社;同时从统计的需要中,我们可以得知“定价”也是一个关键的成员变量。
书籍列表类:书籍列表就是全部的藏书列表,对于该类而言其主要的成员方法是新增、修改、查询(按关键字查询)、统计(按特定时限统计册数与金额)。
借阅记录类:而针对“借阅记录”这个类,其关键的成员变量也一目了然,即借阅人(朋友)、借阅时间。
借阅记录列表类:这也就是所有的借阅记录,因此其主要职责就是添加记录(借出)、删除记录(归还)以及打印借阅记录。
通过上面的分析,我们对这些概念类的了解更加深入,可以重新修改类图,将这些信息加入原先的模型,得到如图13-14所示的结果。
对象图:
UML中对象图与类图具有相同的表示形式。对象图可以看做是类图的一个实例。对象是类的实例;对象之间的链(Link)是类之间的关联的实例。对象与类的图形表示相似,均为划分成三个格子的长方形(下面的两个格子可省略)。最上面的格子是对象名,对象名带有下划线;中间的格子记录属性值。链的图形表示与关联相似。对象图常用于表示复杂类图的一个实例。
顺序图: **
类模型体现了系统的静态结构,用实例模型则从用户的角度对系统的动态行为进行了宏观建模,并通过交互模型将对象与消息有机地结合在一起。但有些时候,我们还需要更好地表示行为的细节** ,这就可以借助于活动图和状态图 来实现。
构件图 描述一个封装的类和它的接口、端口,以及由内嵌的构件和连接件构成的内部结构。构件图用于表示系统的静态设计实现视图 。对于由小的部件构建大的系统来说,构件图是很重要的。构件图是类图的变体 。如图13-25所示,这就是一个构件图。
我们通过构件图将能够理解系统的物理组成结构,但是它并没有办法体现出这些物理组成部分是如何反映在计算机硬件系统之上的。而部署图正是用来弥补这个不足的,它的关注点就在于系统如何部署。部署图,也称为实施图,和构件图一样是面向对象系统的物理方面建模的两种图之一 。
构件图相对来说,是说明构件之间的逻辑关系 ,而部署图则是在此基础上更近一步,描述系统硬件的物理拓扑结构以及在此结构上执行的软件 。部署图可以显示计算结点的拓扑结构和通信路径、结点上运行的软件构件,常常用于帮助理解分布式系统。部署图通常可以用于以下情况的建模工作,如表13-4所示。