第5章分析阶段 通过需求分析阶段,我们以用户可理解的方式表达了需求。然而,软件设计 是一个技术性、专业性的工作,用户的需求和软件设计之间存在较大的“知识鸿 沟”和“表示鸿沟”。通过分析阶段,开发者对需求有了自己的理解,一方面对需 求的正确性、全面性、可行性进行检验,另一方面,建立需求与软件设计之间的 桥梁,从而使得后续阶段中软件开发工作能够顺利开展。因此,分析阶段依旧是 围绕需求展开的,并不涉及到软件设计的细节,但是由于采用了开发者的观点来 分析需求,因此,必然会引入一些与软件相关的概念。例如,如果软件开发采用 了面向对象方法学,在分析阶段将会获取对象模型,并通过动态模型来描述对象 之间是如何通过交互来提供功能的。对象模型,动态模型这些都是软件开发相关 的概念,但是,在分析阶段中,涉及到的类(对象)并非是软件类(对象),而 是“领域类(对象)”,即对应于用户应用中概念的类(对象)。在后续设计阶段, “领域类(对象)”将通过对应的软件类(对象)加以具体实现,分析阶段就是以 这种方式建立了需求与设计之间的桥梁。通过分析阶段,需求获取阶段的结果在 被检验后可能会被修改。 5.1分析阶段的主要内容 分析阶段与三个模型相关,即功能模型、对象模型和动态模型。在需求获取 阶段得到的功能模型是分析阶段的输入,通过分析,建立系统的对象模型和动态 模型是分析阶段的输出。其中,对象模型以面向对象的方式定义了系统的内部构 成,因而主要以类图的方式进行表达。动态模型表达了围绕用例而展开的对象之 间的动态交互过程、某些对象的复杂状态变化以及与软件相关的复杂的业务过程, 动态模型可以用交互图(顺序图或者协同图)、状态图或者活动图进行表达。在 构造对象模型和动态模型的过程中,可能会对功能模型进行修改。 分析阶段是一个迭代的过程,它涉及到以下的一些步骤: 1.类的识别 在采用面向对象方法学进行软件开发时,软件的构成单元是类以及它们的对 象,因此,确定正确的类(对象),就是确定软件的构成。在分析阶段,确定类 的依据是需求和领域知识。值得指出的是,这些类并非是软件概念上的类,它们
5 第 5 章 分析阶段 通过需求分析阶段,我们以用户可理解的方式表达了需求。然而,软件设计 是一个技术性、专业性的工作,用户的需求和软件设计之间存在较大的“知识鸿 沟”和“表示鸿沟”。通过分析阶段,开发者对需求有了自己的理解,一方面对需 求的正确性、全面性、可行性进行检验,另一方面,建立需求与软件设计之间的 桥梁,从而使得后续阶段中软件开发工作能够顺利开展。因此,分析阶段依旧是 围绕需求展开的,并不涉及到软件设计的细节,但是由于采用了开发者的观点来 分析需求,因此,必然会引入一些与软件相关的概念。例如,如果软件开发采用 了面向对象方法学,在分析阶段将会获取对象模型,并通过动态模型来描述对象 之间是如何通过交互来提供功能的。对象模型,动态模型这些都是软件开发相关 的概念,但是,在分析阶段中,涉及到的类(对象)并非是软件类(对象),而 是“领域类(对象)”,即对应于用户应用中概念的类(对象)。在后续设计阶段, “领域类(对象)”将通过对应的软件类(对象)加以具体实现,分析阶段就是以 这种方式建立了需求与设计之间的桥梁。通过分析阶段,需求获取阶段的结果在 被检验后可能会被修改。 5.1 分析阶段的主要内容 分析阶段与三个模型相关,即功能模型、对象模型和动态模型。在需求获取 阶段得到的功能模型是分析阶段的输入,通过分析,建立系统的对象模型和动态 模型是分析阶段的输出。其中,对象模型以面向对象的方式定义了系统的内部构 成,因而主要以类图的方式进行表达。动态模型表达了围绕用例而展开的对象之 间的动态交互过程、某些对象的复杂状态变化以及与软件相关的复杂的业务过程, 动态模型可以用交互图(顺序图或者协同图)、状态图或者活动图进行表达。在 构造对象模型和动态模型的过程中,可能会对功能模型进行修改。 分析阶段是一个迭代的过程,它涉及到以下的一些步骤: 1. 类的识别 在采用面向对象方法学进行软件开发时,软件的构成单元是类以及它们的对 象,因此,确定正确的类(对象),就是确定软件的构成。在分析阶段,确定类 的依据是需求和领域知识。值得指出的是,这些类并非是软件概念上的类,它们
是领域类,通过设计阶段的工作后,领域类将与软件类相对应,换言之,通过软 件类来实现领域类。 2.对象交互描述 围绕每个用例,各个类的对象之间需要进行交互,才能完成用例描述的流程。 对象交互的描述在分析与设计中都具有极其重要的意义。在分析阶段,对象交互 的描述规定了每个类具有的责任,并形成了对象之间的协作关系:而在设计阶段 对对象交互的描述,确定了每个软件类必须提供的操作(需要处理的消息)。不 同的交互方式将最终对系统的可维护性、可扩展性、性能等产生决定性影响。同 时,通过交互方式的描述也可以进一步发现前期需求中的不足,以及发现更多的 相关的类(对象)。 3.类行为刻画 部分类可能具备复杂的行为,特别是其行为受到其状态的影响。在这种情况 下,我们需要描述其可能的状态,以及状态之间的转换条件。我们通常可以采用 状态图来对类的行为进行刻画。当然,那些不具备复杂的状态的类并不需要构造 状态图。 4.对象模型构建 在识别类(对象)、描述对象交互行为的基础上,我们可以形成完整的对象模 型。各个类的属性、操作可以通过前述的分析得到。同时,在对象模型中,类之 间的关系也将得到表达,包括关联和泛化关系。 5.迭代和检查 以上四个步骤不是一个线性的过程。实际上,类的识别、对象交互描述和行 为刻画、对象模型构建构成一个相互影响的迭代序列:识别出来的类的对象将参 与交互过程,在描述交互过程中,会引入新的类(对象)。通过多轮迭代后,最 终得到的模型必须是正确的、完整的、一致的和现实的。所谓正确的,指的是模 型确实代表了实际的需求:模型是完整的,意思是每一个场景包括意外场景都得 到了描述:模型的一致性指的是模型中的元素互相不冲突:模型是现实的,意味 着模型是可以得到实现的。 分析阶段得到的模型依旧表述在软件需求规格说明文档中,并且主要是对系 统模型这一章进行修改和细化。具体来说,对用例模型这一小节,可能会带来修 改,同时补充对象模型和动态模型这两小节的内容
是领域类,通过设计阶段的工作后,领域类将与软件类相对应,换言之,通过软 件类来实现领域类。 2. 对象交互描述 围绕每个用例,各个类的对象之间需要进行交互,才能完成用例描述的流程。 对象交互的描述在分析与设计中都具有极其重要的意义。在分析阶段,对象交互 的描述规定了每个类具有的责任,并形成了对象之间的协作关系;而在设计阶段 对对象交互的描述,确定了每个软件类必须提供的操作(需要处理的消息)。不 同的交互方式将最终对系统的可维护性、可扩展性、性能等产生决定性影响。同 时,通过交互方式的描述也可以进一步发现前期需求中的不足,以及发现更多的 相关的类(对象)。 3. 类行为刻画 部分类可能具备复杂的行为,特别是其行为受到其状态的影响。在这种情况 下,我们需要描述其可能的状态,以及状态之间的转换条件。我们通常可以采用 状态图来对类的行为进行刻画。当然,那些不具备复杂的状态的类并不需要构造 状态图。 4. 对象模型构建 在识别类(对象)、描述对象交互行为的基础上,我们可以形成完整的对象模 型。各个类的属性、操作可以通过前述的分析得到。同时,在对象模型中,类之 间的关系也将得到表达,包括关联和泛化关系。 5. 迭代和检查 以上四个步骤不是一个线性的过程。实际上,类的识别、对象交互描述和行 为刻画、对象模型构建构成一个相互影响的迭代序列:识别出来的类的对象将参 与交互过程,在描述交互过程中,会引入新的类(对象)。通过多轮迭代后,最 终得到的模型必须是正确的、完整的、一致的和现实的。所谓正确的,指的是模 型确实代表了实际的需求;模型是完整的,意思是每一个场景包括意外场景都得 到了描述;模型的一致性指的是模型中的元素互相不冲突;模型是现实的,意味 着模型是可以得到实现的。 分析阶段得到的模型依旧表述在软件需求规格说明文档中,并且主要是对系 统模型这一章进行修改和细化。具体来说,对用例模型这一小节,可能会带来修 改,同时补充对象模型和动态模型这两小节的内容
5.2对象模型的创建 5.2.1类的识别 分而治之是人类处理复杂性的重要手段,因而这也是软件开发中采用的重要 手段。不同的方法学采用了不同的分解手段。传统的结构化方法是将系统按照功 能进行模块分解,而面向对象方法学是按照类(对象)进行系统分解。因此,类 的识别在面向对象软件开发中是一个基本任务。在实践中,许多开发人员从自己 的偏好和经验出发进行对象识别,采用的方法过于随意,这将大大降低面向对象 方法学的好处。 1.类的识别方法 按照面向对象方法学的理念,我们应该从实际问题中去找类,这种找到的类 我们称为问题领域类,它主要是从实际问题出发,反映了实际问题中的业务实体、 业务过程和业务概念。类的寻找有以下方法: (1)文本分析方法:可以从用例文档中、特别是词汇表中找出那些意义重要的 一般名词,它们是潜在的类。 (2)重用已有类概念:如果在该领域已经有一些软件,可以沿用该领域经常采 用的类的概念。 (3)从动态模型中识别:在构建动态模型的过程中,可能会添加新的类。 2.类的类型 在识别类时,我们可以将类分为三种类型,分别为实体类,边界类和控制类。 实体类代表了系统中需要跟踪的持久化信息实体,它是业务实体的直接代表:边 界类负责用户与系统之间的交互,例如系统窗口类;控制类代表了系统中的控制 功能,它负责协调多个对象完成用例流程。三种类别的UML表示方式如图5-1 所示。 <<boundary>> <<control>> <<entity>> View Controller Model 图5-1实体类、边界类和控制类的表示 将类分为这三类体现了软件工程中“视图-模型”相分离的原则,实体类对应于 “模型”,边界类对应于“视图”。模型对应于业务对象,是相对稳定的,而视图则
5.2 对象模型的创建 5.2.1 类的识别 分而治之是人类处理复杂性的重要手段,因而这也是软件开发中采用的重要 手段。不同的方法学采用了不同的分解手段。传统的结构化方法是将系统按照功 能进行模块分解,而面向对象方法学是按照类(对象)进行系统分解。因此,类 的识别在面向对象软件开发中是一个基本任务。在实践中,许多开发人员从自己 的偏好和经验出发进行对象识别,采用的方法过于随意,这将大大降低面向对象 方法学的好处。 1. 类的识别方法 按照面向对象方法学的理念,我们应该从实际问题中去找类,这种找到的类 我们称为问题领域类,它主要是从实际问题出发,反映了实际问题中的业务实体、 业务过程和业务概念。类的寻找有以下方法: (1) 文本分析方法:可以从用例文档中、特别是词汇表中找出那些意义重要的 一般名词,它们是潜在的类。 (2) 重用已有类概念:如果在该领域已经有一些软件,可以沿用该领域经常采 用的类的概念。 (3) 从动态模型中识别:在构建动态模型的过程中,可能会添加新的类。 2. 类的类型 在识别类时,我们可以将类分为三种类型,分别为实体类,边界类和控制类。 实体类代表了系统中需要跟踪的持久化信息实体,它是业务实体的直接代表;边 界类负责用户与系统之间的交互,例如系统窗口类;控制类代表了系统中的控制 功能,它负责协调多个对象完成用例流程。三种类别的 UML 表示方式如图 5-1 所示。 图 5-1 实体类、边界类和控制类的表示 将类分为这三类体现了软件工程中“视图-模型”相分离的原则,实体类对应于 “模型”,边界类对应于“视图”。模型对应于业务对象,是相对稳定的,而视图则
可能变化比较多,通过分离,有效地降低了软件维护的成本。类的这三种类型也 可以类比一个企业内的组织分工,实体类就是那些岗位员工,是真正处理业务的: 边界类就是那些销售和供应人员,负责与外界打交道:控制类是企业中的管理人 员,本身不干活,负责协调大家。一个合理的组织分工这三者都是需要的。 3.类识别注意点 在识别类的时候,有以下注意点: 1)类的命名:在类命名时,首先应该用实际业务中的名字,同时,名字应该 相对通用,而不是过早限定具体的方式。例如,在教室预定系统中,代表 终端的类,可以是MobileTerminal,也可以是MobilePhone, MobileTerminal不限于MobilePhone,是不是客户端只支持MobilePhone 可以留待后续设计时决定,那么用MobileTerminal就会比较通用。 2) 虽然我们一再强调类应该代表现实中的概念,然而我们毕竟在开发软件, 所以在识别类时,可能会专门创造一些用来记忆“公共信息”的类,以避免 信息的重复。例如,在现实生活中,每一件商品上都是有商品信息(名称、 产地、成分等等)的,但是同类商品上的这些商品信息都是一样的,为了 避免重复,我们可以添加一个ProductSpecificaion类,记录商品信息, Product类本身只保存商品编号、生产日期等信息,从而避免信息的冗余。 3) 在识别类时,也有可能依据软件的具体需要,适当添加一些实际生活中并 不存在、但是出于软件的特点而添加的类,控制类就属于这种情景。 5.2.2对象模型的表达 识别出类后,我们将利用类图来表示对象模型。类图由类和类之间的关联关 系构成。分析阶段的对象模型主要是对真实世界中概念类的表示,而不是软件对 象的表示。对象模型中要考虑: 1.属性的添加 每一个类需要添加属性,类的对象的属性取值保存和刻画了对象当前的状态。 每一个类都有许多细节信息,因此可以作为属性的数据项也很多,但是,我们并 不需要也不可能把一切数据项都作为属性。我们可以根据该属性是否对我们当前 的应用有价值来确定是否需要添加该属性。 另外一个问题是哪些应该作为属性,哪些作为类来建模。一般而言,属性应
可能变化比较多,通过分离,有效地降低了软件维护的成本。类的这三种类型也 可以类比一个企业内的组织分工,实体类就是那些岗位员工,是真正处理业务的; 边界类就是那些销售和供应人员,负责与外界打交道;控制类是企业中的管理人 员,本身不干活,负责协调大家。一个合理的组织分工这三者都是需要的。 3. 类识别注意点 在识别类的时候,有以下注意点: 1) 类的命名:在类命名时,首先应该用实际业务中的名字,同时,名字应该 相对通用,而不是过早限定具体的方式。例如,在教室预定系统中,代表 终 端 的 类 , 可 以 是 MobileTerminal , 也 可 以 是 MobilePhone , MobileTerminal 不限于 MobilePhone,是不是客户端只支持 MobilePhone 可以留待后续设计时决定,那么用 MobileTerminal 就会比较通用。 2) 虽然我们一再强调类应该代表现实中的概念,然而我们毕竟在开发软件, 所以在识别类时,可能会专门创造一些用来记忆“公共信息”的类,以避免 信息的重复。例如,在现实生活中,每一件商品上都是有商品信息(名称、 产地、成分等等)的,但是同类商品上的这些商品信息都是一样的,为了 避免重复,我们可以添加一个 ProductSpecificaion 类,记录商品信息, Product 类本身只保存商品编号、生产日期等信息,从而避免信息的冗余。 3) 在识别类时,也有可能依据软件的具体需要,适当添加一些实际生活中并 不存在、但是出于软件的特点而添加的类,控制类就属于这种情景。 5.2.2 对象模型的表达 识别出类后,我们将利用类图来表示对象模型。类图由类和类之间的关联关 系构成。分析阶段的对象模型主要是对真实世界中概念类的表示,而不是软件对 象的表示。对象模型中要考虑: 1. 属性的添加 每一个类需要添加属性,类的对象的属性取值保存和刻画了对象当前的状态。 每一个类都有许多细节信息,因此可以作为属性的数据项也很多,但是,我们并 不需要也不可能把一切数据项都作为属性。我们可以根据该属性是否对我们当前 的应用有价值来确定是否需要添加该属性。 另外一个问题是哪些应该作为属性,哪些作为类来建模。一般而言,属性应
该是基本数据类型(如整形、浮点型、布尔型、字符串型)。如果一个属性是复 杂数据类型(可以进一步分成多个数据项的数据),最好把它作为单独的类,然 后将这两个类关联起来。 2.关联的添加 关联刻画了两个类结构方面的联系。那么,我们需要把所有可能的关联关系 都刻画出来吗?显然并不必要。因为从某种意义上讲,世界上的万事万物都是关 联的,小世界定理甚至告诉我们世界上任意两个人只要通过不多于六个中间人就 可以联系起来。那么我们需要添加什么样的关联关系呢?以下为一些指南: (1)添加那些重要的、需要持续一段时间的关联信息: (2)添加那些能够表示聚合、组合这种“整体-部分"关系的关联信息; (3)在此阶段,我们只要从领域知识出发来考虑关联,并不需要考虑关联将来 如何在软件中实现的问题: (4)不要添加那些可以从其他关系中推导出来的关联关系。 完整的关联信息包括了:关联的方向、关联的名字、多重性、角色。 3.对象模型的精化 对象模型的构建并不是一次完成的。我们应该对建立的对象模型进行多次重 新检查并在必要的时候进行模型的调整。 在模型中可能会发现如下问题: 1) 重复的定义:由于我们通过多种渠道(如通过文本分析、构建交互图、依 据领域知识等)去识别类,因此有时候可能将一个类重复定义了两次,或 者将同一属性、同一操作定义了两次,我们需要将它们进行合并: 2)应该建模为类的属性,或者不必要作为类的属性:有些属性类型比较复杂, 或者有相应的操作与其关联,那么最好将其建模为类,而相反,有些类只 有很少的属性,并且只有写入和读取的操作,那么就可以简化其为属性。 随着分析的深入,可能会发现以下情况从而可以建立类之间的“泛化-例化” 结构: 1) 一个概念在现实中可以分成子类型,并且子类型具有不同的行为,那么可 以将子类型建模成子类。但是值得注意的是,并不是在现实中的子类型都 需要建模成子类,过于复杂的继承结构也会造成软件的复杂,因此只有在 子类型对于应用有意义时,才需要建模成子类。 2) 发现多个类具有共同点,因此抽象出一个父类。通过抽象出的父类,并定
该是基本数据类型(如整形、浮点型、布尔型、字符串型)。如果一个属性是复 杂数据类型(可以进一步分成多个数据项的数据),最好把它作为单独的类,然 后将这两个类关联起来。 2. 关联的添加 关联刻画了两个类结构方面的联系。那么,我们需要把所有可能的关联关系 都刻画出来吗?显然并不必要。因为从某种意义上讲,世界上的万事万物都是关 联的,小世界定理甚至告诉我们世界上任意两个人只要通过不多于六个中间人就 可以联系起来。那么我们需要添加什么样的关联关系呢?以下为一些指南: (1) 添加那些重要的、需要持续一段时间的关联信息; (2) 添加那些能够表示聚合、组合这种“整体-部分”关系的关联信息; (3) 在此阶段,我们只要从领域知识出发来考虑关联,并不需要考虑关联将来 如何在软件中实现的问题; (4) 不要添加那些可以从其他关系中推导出来的关联关系。 完整的关联信息包括了:关联的方向、关联的名字、多重性、角色。 3. 对象模型的精化 对象模型的构建并不是一次完成的。我们应该对建立的对象模型进行多次重 新检查并在必要的时候进行模型的调整。 在模型中可能会发现如下问题: 1) 重复的定义:由于我们通过多种渠道(如通过文本分析、构建交互图、依 据领域知识等)去识别类,因此有时候可能将一个类重复定义了两次,或 者将同一属性、同一操作定义了两次,我们需要将它们进行合并; 2) 应该建模为类的属性,或者不必要作为类的属性:有些属性类型比较复杂, 或者有相应的操作与其关联,那么最好将其建模为类,而相反,有些类只 有很少的属性,并且只有写入和读取的操作,那么就可以简化其为属性。 随着分析的深入,可能会发现以下情况从而可以建立类之间的“泛化-例化” 结构: 1) 一个概念在现实中可以分成子类型,并且子类型具有不同的行为,那么可 以将子类型建模成子类。但是值得注意的是,并不是在现实中的子类型都 需要建模成子类,过于复杂的继承结构也会造成软件的复杂,因此只有在 子类型对于应用有意义时,才需要建模成子类。 2) 发现多个类具有共同点,因此抽象出一个父类。通过抽象出的父类,并定