天涯一飘絮

导航

 
本章要点

¢  UML基础

¢ 对象建模技术

¢ 面向对象分析

¢ 面向对象设计

面向对象编程方法学是C#编程的指导思想。进行C#编程的第一步是利用对象建模技术(Object Modeling Technique,OMT)来分析目标问题,抽象出相关对象的共性,对它们进行分类,并分析各类之间的关系,再用类来描述同一类对象,归纳出类之间的关系。Coad和Yourdon在对象建模技术、面向对象编程和知识库系统的基础之上设计了一整套面向对象的方法,分为面向对象分析(Object-Oriented Analysis,OOA)和面向对象设计(Object-Oriented Design,OOD)。对象建模技术、面向对象分析和面向对象设计共同构成了系统设计的过程,如图6-1所示。这是编写代码的基础。

图6-1  系统设计流程

在进行对象建模、面向对象分析和设计的过程中,需要使用建模语言来描述分析的过程和结果。统一建模语言(Unified Modeling Language,UML)是为了这个目标而设计的一种标准通用的设计语言。任何想要真正理解面向对象编程思想的人,都需要具备一定的UML知识。

限于本书的篇幅和目的,本章只能蜻蜓点水式地简单介绍对象建模技术、面向对象分析、面向对象设计和UML的基础知识。这些知识能够满足学习本书后面内容的需要,但是并不足以使你成为面向对象技术方面的专家。志存高远的读者应该进一步阅读这方面的专著。

6.1  UML基础

1997年,对象管理组织(Object Management Group,OMG)发布了UML。UML的目标之一就是为开发团队提供标准通用的设计语言,以便更有效地开发和构建计算机应用。UML提出了一套统一的标准建模符号,便于人们交流系统架构和设计规划。UML现在已经获得了业界的认同,成为一种事实的标准,已广泛应用于系统设计中。

6.1.1  简介

UML不是一种方法学,而是一种描述语言,它提供了多种类型的模型描述图(diagram),当在某种给定的方法学中使用这些图时,人们就能更容易理解和交流设计思想。UML的图可划分为如下三种类型。

— 静态图(static diagram):描述了那些不发生变化的软件元素的逻辑结构,描绘了类、对象、数据结构及其存在于它们之间的关系。

— 动态图(dynamic diagram):展示了在运行期间的软件实体的变化,描绘了执行流程、实体改变状态的方式。

— 物理图(physical diagram):显示了软件实体的不变化的物理结构,描绘库文件、字节文件、数据文件等,以及存在于它们之间的关系。

表6-1说明了三类图中最常用的一些UML图,以及它们适用的软件开发阶段。本节将主要介绍其中的用例图(use case diagram)、类图(class diagram)、对象图(object diagram)、序列图(sequence diagram)、状态图(statechart diagram)、活动图(activity diagram)、组件图(component diagram)和部署图(deployment diagram)。

表6-1  常用的UML图

   

   

分析阶段

设计阶段

实现阶段

静态图

用例图

ü

 

 

 

对象图

ü

ü

 

 

类图

ü

ü

ü

 

组件图

 

ü

ü

 

部署图

 

 

ü

动态图

协作图

ü

ü

ü

 

序列图

ü

ü

ü

 

活动图

ü

 

 

 

状态图

ü

ü

ü

物理图

文件、数据库等

ü

ü

ü

提示  Microsoft Visio可以用来方便地绘制UML图。Visual Studio 2005的类关系图也可以显示类似UML的图,但是与标准的UML稍有不同。

6.1.2  用例图

用例图描述了系统提供的一个功能单元。用例图的主要目的是帮助开发团队以一种可视化的方式来理解系统的功能需求,包括基于基本流程的“角色”之间的关系,以及系统内用例之间的关系。用例图一般用于表示用例的组织关系,要么是整个系统的全部用例,要么是完成具有功能(例如,所有安全管理相关的用例)的一组用例。

用例(use case)指的是系统的功能,它是系统某个功能的所有执行动作的集合。用例是从一个用户的观点来描述的。这个用户告诉系统去做一些特定的事情。一个用例捕获一个事件的可视化序列,这个事件是一个系统对单个用户的激励(stimulus)的响应过程。

动作者(actor)表示系统用户能扮演的角色(role) 。这些用户可能是人,也可能是其他的计算机、一些硬件,或者甚至是其他的软件系统。对用例的唯一要求是,它们必须位于用例描述的系统部分之外,它们必须能刺激系统部分,并接收返回。

用例描述了当动作者之一给系统特定的刺激时的系统活动。这些活动用文本来描述。它描述了触发用例的刺激的本质,输入和输出到其他活动者,以及从输入到输出的活动。用例文本通常也描述每一个活动可能的错误和系统应采取的补救措施。

在用例图中,用椭圆来表示用例,并将用例的名称放在椭圆的中心或椭圆下面的中间位置。人形符号用来表示角色(用户)。角色和用例之间的关系使用简单的线段来描述,表示角色可以操作此用例。

在用例图中,用一个方框来表示系统的边界。所有系统用例都放在框内,所有动作者都位于框外。动作者和用例之间用直线相连。方框内的每一件事物都是系统的一部分,方框外的每一件事物都是系统的外部。用例图也可以表示方框内的系统用例之间的关系,最常见的是“使用关系”,用带箭头的直线来表示,箭头指向被使用的用例。还有一种关系是扩展关系,用来表示继承。

图6-2显示了一个用例图。用例图通常用于表达系统或者系统范畴的高级功能。在图中可以很容易地看出该系统所提供的功能。这个系统允许乐队经理查看乐队CD的销售统计报告及排行榜报告。它也允许唱片经理查看特定CD的销售统计报告和这些CD在排行榜的报告。这个图还告诉我们,系统将通过一个名为“排行榜报告服务”的外部系统来提供排行榜报告。

用例图不会列出系统不能完成的功能。例如,图6-2所示的系统不能提供给乐队经理收听排行榜上不同专辑中的歌曲的方法,也就是说,系统没有引用一个叫做“收听排行榜上的歌曲”的用例。如果在用例图中提供清楚的、简要的用例描述,项目赞助商就能很容易地看出系统是否提供了必需的功能。

图6-2  用例图示例

6.1.3  类图和对象图

类图表示不同的实体(人、事物和数据)如何彼此相关,显示了系统的静态结构。类图可用于表示逻辑类,逻辑类通常就是业务人员所谈及的事物种类,比如摇滚乐队、CD、广播剧,或者贷款、住房抵押、汽车信贷及利率的抽象描述。类图还可用于表示实现类,实现类就是程序员要编写的类。实现类图与逻辑类图可能会用来描述一些相同的类。然而,实现类图与逻辑类图不会使用相同的描述属性。

类图是一个分为三个部分的矩形。最上面的部分显示类的名称,中间部分显示类的属性,最下面的部分显示类的操作(或者说“方法”)。实际上,最常用、最简单的类图就是一个在里面显示了类名的长方形,因为在UML中,大多数类只要有一个能够清楚表达的命名就可以了。

在类名部分还可以显示类的构造类型。类的构造型显示在一对双角括符号“« »”之间,经常放在类的名称上面。常见的构造类型包括实现类(直接显示类名)、接口(在类名上面显示 «interface»),以及工具类(在类名上面显示 «utility»)。如果类名用斜体表示,或者在类名下面标上{abstract},就表示这个类是一个抽象类。

在属性和方法的前面有一个字符用来表示属性或方法的作用域,它们的意义如下:

—“-”表示属性或方法是私有的(private);

—“#”表示属性或方法是保护的(protected);

—“+”表示属性或方法是公用的(public)。

紧接在属性或方法的参数名称的冒号(:)号之后,显示了属性的类型或方法的参数的类型。方法的返回值类型显示在方法后面的冒号之后。

图6-3显示了一个类Person的类图,它对应的类的C#源代码如下:

Person

+name: string

+sex: char

-age: int

+Work(in type: string): void

+Person(in name: string, in sex: char, in age: int): void

+Speak(): void

+Eat(): void

图6-3  类图示意

class Person

{

    public string name;

    public char sex;

    private int age;

    public Person(string name, char sex, int age)

    {

    }

    public void Eat()

    {

    }

    public void Speak()

    {

    }

    public void Work(string type)

    {

    }

}

对象图用来表示类的实例化对象。对象图用一个两层的矩形来表示,上层标识对象名和类名,下层标识对象的实例化属性值。下面的代码将创建一个Person类的对象mary:

Person mary = new Person("Mary", 'F', 24);

对象mary的对象图如图6-4所示。

mary: Person

name: string   ="Mary"

sex: char      ='F'

age: int       =24

图6-4  对象图示例

在一个系统中,类之间存在多种关系,如下所示。

— 继承(inheritance):继承是指一个类从其父类派生而来,继承了父类的属性和方法。基于类的继承叫做一般化(generalization),基于接口的继承,叫做实现(realization)。

— 关联(association):类之间的关联大多用来表示变量实例持有对其他对象的引用,这种关系是半永久的,但没有包含关系。

— 依赖(dependency):依赖是不同类的实例之间的暂时关系。

— 聚合(aggregation):聚合是关联的一种特殊形式,它意味着一种整体/部分(whole/part)的关系,但是部分也可以作为其他整体的组分,而且部分和整体之间也没有生命期的依赖。

— 组合(composition):组合是聚合的一种特殊形式,组合的关联性比聚合更强,部分只能作为唯一的一个整体的部分,而且部分的生命周期依赖于整体的生命周期。

UML类图对这些关系的表示方法如图6-5所示。具有关联、聚合和组合关系的两个对象之间可能是没有数量关系的一种联系,也可能存在数量关系,比如1对1(不标识)、0个或1个(标识为0…1)、0个或多个(标识为0…*或0…n)、1个或多个(标识为1…*或1…n)或者确切的数字(直接标识数字)。

图6-6显示了一个包含了图6-2中的对象的类图。其中包括一个继承关系和两个关联关系。CDSalesReport类继承自Report类。一个CDSalesReport类与一个CD类关联,但是CD类并不知道关于CDSalesReport类的任何信息。CD类和Band类都彼此知道对方,两个类彼此都可以与一个或者多个对方类相关联。

图6-5  UML类图之间的关系表示方法

图6-6  包含关系的类图

图6-7显示了一个包含多种关系的类图的另一个例子。Person类实现了IHuman接口,Author类继承了Person类;Book类与Author类之间的关联是1对多的,即一本书可能有一个或多个作者;Person读书,这是一种暂时的单向依赖;Book由一个或多个Page组成,每一个Page只能作为一本Book的一部分,这是一种组合关系;Bookshelf里可以不放或者放多本Book,Book也可以放在其他的Bookshelf中,Bookshelf的存在并不能影响Book的存在性,这是一种聚合关系。

图6-7  一个包含多种关系的类图

表示各对象之间的关系的对象图说明了系统在某一个特定时刻的状态,经常叫做系统的快照(snapshot)。

 内幕:UML与源代码

UML是一种设计语言,它的目的不是表现细节,而是表现结构,仅仅展示必要的细节。因此,UML不可能与源代码一一对应,只存在结构上的对应关系。作为一种参考,下面列出了图6-7中的类图的C#源代码:

interface IHuman

{

}

class Person : IHuman

{

    void Read(Book book)

    {

         // …

    }

}

class Author : Person

{

    public Book[] books;

}

class Book

{

    public Author author;

    public Page[] pages;

}

class Page

{

}

class Bookshelf

{

    public Book[] books;

}

6.1.4  序列图

序列图显示具体用例(或用例的一部分)的详细流程。它几乎是自描述的,并且显示了流程中不同对象之间的交互关系,同时还可以很详细地显示对不同对象的各种调用。

序列图有两个维度:垂直维度以发生的时间顺序显示消息/调用的序列;水平维度显示对象实例之间的交互。

对象之间的交互包括:

— 调用(call):一个对象调用另一个对象(或者自己)的方法。

— 返回(return):返回一个值作为方法调用的结果。

— 发送(send):一个对象给另一个对象(或者自己)异步发送一个消息。

— 创建(create):一个对象实例化另一个对象。

— 销毁(destroy):一个对象销毁另一个对象(或者自己)。

序列图的绘制非常简单。图的顶部的框表示类的实例(对象)。在框中,类实例名称和类名称之间用空格/冒号/空格来分隔(例如,gen : ReportGenerator)。如果某个类实例向另一个类实例发送一条消息,则绘制一条具有指向接收类实例的开箭头的连线,并把消息/方法的名称放在连线上面。对于某些特别重要的消息,可以绘制一条具有指向发起类实例的开箭头的虚线,将返回值标注在虚线上。包括返回值的虚线,有助于序列图的阅读。

阅读序列图也非常简单。从左上角启动序列的“驱动”类实例开始,然后顺着每条消息往下阅读。

图6-8显示了一个序列图的例子。图中的序列图显示了许多的细节(比如,其中显示了每条被发送消息的返回消息,这是可选的),一般的序列图可能要简单得多。通过阅读这个序列图,就能明白如何创建一个CD销售报告。其中的aProc对象表示驱动类实例。aProc向名为gen的ReportGenerator类实例发送一条消息。该消息被标为generateCDSalesReport,表示ReportGenerator对象实现了这个消息处理程序。进一步理解可发现,generateCD SalesReport消息标签在括号中包括了一个cdId,表明aServlet随该消息传递一个名为cdId的参数。当gen实例接收到一条generateCDSalesReport消息时,它会接着调用CDSalesReport类,并返回一个aCDReport的实例。然后gen实例对返回的aCDReport实例进行调用,在每次消息调用时向它传递参数。在该序列的结尾,gen实例向它的调用者aProc返回一个aCDReport。

图6-8  序列图示例

6.1.5  状态图

状态图表示某个类所处的不同状态和该类的状态转换信息。每个类都有状态,但不是每个类都应该有一个状态图。只有当行为的改变和状态有关时才创建状态图。一般只描述在系统活动期间具有三个或更多潜在状态的类的状态图。

状态图的符号集包括5个基本元素:初始起点,它使用实心圆来绘制;状态之间的转换,它使用带箭头的线段来绘制;状态,它使用圆角矩形来绘制;判断点,它使用空心圆来绘制;一个或者多个终止点,它们使用内部包含实心圆的圆来绘制。要想绘制状态图,首先需要绘制起点和一条指向该类的初始状态的转换线段。状态本身可以在图上的任意位置绘制,然后只需使用状态转换线条将它们连接起来。

图6-9显示了一个培训班的状态图。图的中心有一个判断点,如果有学员退学,则需要判断是否还有学员继续学习:如果还有,则培训班继续,否则只好被迫停止。

图6-9  一个培训班的状态图

6.1.6  活动图

活动图表示在处理某个活动时,两个或者更多类对象之间的过程控制流。活动图可用于在业务单元的级别上对更高级别的业务过程进行建模,或者对低级别的内部类操作进行建模。

活动图的符号集与状态图中使用的符号集类似。像状态图一样,活动图也从一个连接到初始活动的实心圆开始。活动是通过一个圆角矩形(活动的名称包含在其内)来表示的。活动可以通过转换线段连接到其他活动,或者连接到判断点,这些判断点连接到由判断点的条件所保护的不同活动。结束过程的活动连接到一个终止点(就像在状态图中一样)。作为一种选择,活动可以分组为泳道(swimlane),泳道用于表示实际执行活动的对象。

图6-10中显示的活动图有两个泳道,因为有两个对象控制着各自的活动:乐队经理和报告工具。整个过程首先从乐队经理选择查看他的乐队销售报告开始。然后报告工具检索并显示他管理的所有乐队,并要求他从中选择一个乐队。在乐队经理选择一个乐队之后,报告工具就检索销售信息并显示销售报告。该活动图表明,显示报告是整个过程中的最后一步。

图6-10  活动图示例

6.1.7  组件图

组件图提供系统的物理视图,它的用途是显示系统中的软件与其他软件组件(例如,库函数)的依赖关系。组件图可以在一个非常高的层次上显示,从而仅显示粗粒度的组件,也可以在组件包层次上显示。

图6-11中的组件图显示了四个组件:Reporting Tool、Billboard Service、ASP .NET和ADO .NET。从Reporting Tool组件指向Billboard Service、ASP .NET API和ADO .NET组件的带箭头的线段,表示Reporting Tool依赖于那三个组件。

6.1.8  部署图

部署图表示该软件系统如何部署到硬件环境中。它的用途是显示该系统不同的组件将在何处物理地运行,以及它们将如何彼此通信。因为部署图是对物理运行情况进行建模,系统的生产人员就可以很好地利用这种图。

部署图中的符号包括组件图中所使用的符号元素,另外还增加了几个符号,包括节点的概念。一个节点可以代表一台物理机器,或代表一个虚拟机器节点(例如,一个大型机节点)。用三维立方体来表示节点,节点的名称位于立方体的顶部。所使用的命名约定与序列图中相同:[实例名称] : [实例类型](例如,"w3.reporting.myco.com : Application Server")。

图6-11  组件图示例

图6-12中的部署图表明,用户使用运行在本地机器上的浏览器访问Reporting Tool,并通过公司intranet上的HTTP协议连接到Reporting Tool组件。这个工具实际运行在名为w3.reporting.myco.com的服务器上。Reporting Tool通过ADO .NET与数据库相连。除了与报告数据库通信外,Report Tool组件还通过HTTPS上的SOAP与Billboard Service进行通信。

图6-12  部署图示例

 

6.2  对象建模技术

对象建模技术是美国通用电气公司提出的一套系统开发技术。它以面向对象的思想为基础,通过对问题进行抽象,构造出一组相关的模型,从而全面地描述问题领域的结构。对象建模技术把分析时收集到的信息构造在三类模型中,即功能模型、对象模型和动态模型。功能模型定义系统“做什么”,对象模型定义系统“对谁做”,动态模型定义系统“如何做”。三个模型从不同的角度对系统进行描述,分别着重于系统的一个侧面,组合起来构成对系统的完整描述。

6.2.1  功能模型

功能模型着重于系统内部数据的传送和处理。功能模型能够说明,从输入数据能够计算出什么样的输出数据,但是没有考虑参加计算的数据按什么时序来执行。功能模型由多个数据流图组成,它们指明从外部输入,通过操作和内部存储,直到外部输出的整个数据流情况。功能模型还包括了对象模型内部数据间的限制。功能模型中的数据流图往往形成一个层次结构,一个数据流图的过程可以由下一层的数据流图作进一步的说明。UML使用用例图和活动图来描述功能模型。

建立功能模型的主要步骤如下:

(1)确定输入和输出值。

(2)用数据流图表示功能的依赖性。

(3)具体描述每个功能。

(4)确定限制。

(5)确定功能优化的准则。

6.2.2  对象模型

对象模型描述系统的静态结构,包括类和对象,它们的属性和操作,以及它们之间的关系。构造对象模型的目的在于找出与应用密切相关的概念。对象模型用包含对象和对象之间关系的图来表示。UML使用类图和对象图来描述对象模型。

使用OMT 建立对象模型的主要步骤如下:

(1)确定对象类。

(2)定义数据词典,并利用它来描述类的属性和类之间的关系。

(3)用继承来组织和简化类的结构和类之间的关系。

(4)测试访问路径。

(5)根据对象之间的关系和对象的功能将对象分组建立模块。

比如,如果需要描述一个图形系统,我们首先就要确定我们的研究对象图形(点、线、多边形、圆形等),图形的属性(点数、边数等),图形的操作(画法)等。然后,归纳各种图形之间的关系,比如多边形和圆形都从图形派生而来,三角形和四边形又从多边形派生而来。最后得出类之间的层次关系,以及每一个类的详细属性和操作。

6.2.3  动态模型

动态模型着重于系统的控制逻辑,考察在任何时候对象及其关系的改变,描述这些涉及时序和改变的状态。

动态模型用状态图和事件跟踪图来描述。状态图是状态和事件以及它们之间的关系所形成的网络,侧重于描述每一类对象的动态行为。事件跟踪图则侧重于说明系统执行过程中的一个特点场景,描述完成系统某个功能的一个事件序列。对象到对象的单个消息叫做一个事件。在系统的一个特定环境下发生的一系列事件叫做一个场景(scenarios)。场景通常起始于一个系统外部的输入事件,结束于一个系统外部的输出事件。在一个场景中一系列事件和交换事件的对象都可以放在一个事件跟踪图中表示。UML使用状态图和序列图来描述动态模型,序列图对应于事件跟踪图。

建立动态模型的主要步骤如下:

(1)准备典型的交互序列的场景。

(2)确定对象之间的事件,为每个场景建立事件跟踪图。

(3)为每个系统准备一个事件流图。

(4)为具有重要动态行为的类建立状态图。

(5)检验不同状态图中共享的事件的一致性和完整性。

 

6.3  面向对象分析

面向对象分析属于软件开发过程中的问题定义阶段,其目标是清晰、精确地定义问题领域。传统的系统分析产生一组面向过程的文档,定义目标系统的功能;面向对象分析则产生一种描述系统功能和问题领域的基本特征的综合文档。

6.3.1  原则

面向对象分析的主要原则如下。

1.抽象

从许多事物中舍弃个别的、非本质的特征,抽取共同的、本质性的特征,就叫做抽象。抽象是形成概念的必须手段。

抽象原则有两方面的意义:第一,尽管问题域中的事物是很复杂的,但是分析员并不需要了解和描述它们的一切,只需要分析研究其中与系统目标有关的事物及其本质性特征。第二,通过舍弃个体事物在细节上的差异,抽取其共同特征而得到一批事物的抽象概念。

抽象是面向对象方法中使用最为广泛的原则。抽象原则包括过程抽象和数据抽象两个方面。过程抽象是指,任何一个完成确定功能的操作序列,其使用者都可以把它看做一个单一的实体,尽管实际上它可能是由一系列更低级的操作完成的。数据抽象是指根据施加于数据之上的操作来定义数据类型,并限定数据的值只能由这些操作来修改和观察。数据抽象是面向对象分析的核心原则。它强调把数据(属性)和操作(服务)结合为一个不可分的系统单位(即对象),对象的外部只需要知道它做什么,而不必知道它如何做。

2.封装

封装就是把对象的属性和服务结合为一个不可分的系统单位,并尽可能隐蔽对象的内部细节。

3.继承

特殊类的对象拥有的其一般类的全部属性与服务,称作特殊类对一般类的继承。

在面向对象分析中运用继承原则,就是在每个由一般类和特殊类形成的一般—特殊结构中,把一般类的对象实例和所有特殊类的对象实例都共同具有的属性和服务,一次性地在一般类中进行显式定义。在特殊类中不再重复地定义一般类中已定义的东西,但是在语义上,特殊类却自动地、隐含地拥有它的一般类(以及所有更上层的一般类)中定义的全部属性和服务。继承原则的好处是:使系统模型比较简练也比较清晰。

4.分类

就是把具有相同属性和服务的对象划分为一类,用类作为这些对象的抽象描述。分类原则实际上是抽象原则运用于对象描述时的一种表现形式。

5.聚合

聚合的原则是:把一个复杂的事物看成若干比较简单的事物的组装体,从而简化对复杂事物的描述。

6.关联

关联是人类思考问题时经常运用的思想方法:通过一个事物联想到另外的事物。能使人发生联想的原因是事物之间确实存在着某些联系。

7.消息通信

这一原则要求对象之间只能通过消息进行通信,而不允许在对象之外直接地存取对象内部的属性。通过消息进行通信是由于封装原则而引起的。在OOA中要求用消息连接表示出对象之间的动态联系。

8.粒度控制

一般来讲,人在面对一个复杂的问题域时,不可能在同一时刻既能纵观全局,又能洞察秋毫。因此需要控制自己的视野:考虑全局时,注意其大的组成部分,暂时不详察每一部分的具体的细节;考虑某部分的细节时则暂时撇开其余的部分。这就是粒度控制原则。

9.行为分析

现实世界中事物的行为是复杂的。由大量的事物所构成的问题域中各种行为往往相互依赖、相互交织。

6.3.2  阶段

面向对象分析过程可分为问题领域分析和应用分析两个阶段。

问题领域分析是软件开发的基本组成部分,目的是使开发人员了解问题领域的结构,建立大致的系统实现环境。问题领域分析给出一组抽象概念(从高层来表示问题领域知识,常常超出当前应用的范围)作为特定系统需求开发的参考。问题领域分析实际上是一种学习过程。软件开发人员在这个阶段应该尽可能地理解当前系统中与应用有关的知识,应该放开思维,放宽考虑的范围,尽可能地标识与应用有关的概念。问题领域分析的边界可能很模糊。有了广泛的问题领域知识,涉及到具体的应用时,就可以更快地进入状态,掌握应用的核心知识。而且,在用户改变对目标系统的需求时,广泛的分析可以帮助我们预测出目标系统在哪些方面会发生哪些变化。通常进行小组分析,小组成员可以包括领域专家和分析员等。在分析过程中,应该标识出系统的基本概念(对象、类、方法、关系等)、识别问题领域的特征,并把这些概念集成到问题领域的模型中。问题领域的模型必须包含概念之间的关系,以及每个概念的全部信息。标识出来的相关概念应该根据信息内容来有机地融合到问题领域的综合视图中。

应用分析是依据在问题领域分析时建立起来的问题领域模型来进行的。应用分析时,把问题领域模型用于当前特定的应用之中。首先,通过收集到的用户信息来对问题领域进行取舍,把用户需求作为限制条件来使用,以缩减问题领域的信息量。因此,问题领域分析的视野大小直接影响到应用分析保留的信息量。一般来说,问题领域分析阶段产生的模型并不需要用程序设计语言来表示,而应用分析阶段产生的影响条件则需要用某种程序设计语言来表示。模型识别的要求可以针对一个应用,也可以针对多个应用。通常我们着重考虑两个方面,即应用视图和类视图。在类视图中,必须对每个类的属性和操作进行细化,并表示出类之间的相互作用关系。

6.3.3  目标

Coad和Yourdon 认为,面向对象分析主要应该考虑与特定应用有关的对象,以及对象之间在结构和相互作用上的关系。在面向对象分析中,需要建立分析模型来描述系统的功能。

面向对象分析需要完成如下两个任务:

— 形式化地说明所面对的应用问题,最终成为软件系统基本构成的对象,以及系统所必须遵从的、由应用环境所决定的规则和约束条件。

— 明确地规定构成系统的对象如何协同工作和完成指定的功能。

通过面向对象分析所建立的系统模型是以概念为中心的,因此称为概念模型。概念模型由一组相关的类组成。面向对象分析可以通过自顶向下地逐层分解来建立系统模型,也可以自底向上地从已经定义的类出发,逐步构造新的类。概念模型的构造和评审由如下5个层次构成:

— 类和对象层

— 属性层

— 服务层

— 结构层

— 主题层

这5个层次不是构成软件系统的层次,而是分析过程中的层次。也可以说是问题的不同侧面。每个层次的工作都为系统的规格说明增加了一个组成部分。当5个层次的工作全部完成时,面向对象分析的任务也就完成了。

在实际操作中,面向对象分析的目标是得出问题领域的功能模型、对象模型和动态模型,并用相应的UML图将它们表示出来。

6.3.4  步骤

面向对象分析通常按照下面的步骤来进行:

(1)标识对象和类。可以从应用领域开始,逐步确定形成整个应用的基础类和对象。这一步需要分析领域中目标系统的责任,调查系统的环境,从而确定对系统有用的类和对象。

(2)标识结构。典型的结构有两种,即一般—特殊结构和整体—部分结构。一般—特殊结构表示一般类是基类,特殊类是派生类。比如,汽车是轿车和卡车的基类,这是一种一般—特殊结构。整体部分结构表示聚合,由属于不同类的成员聚合成为新的类。比如,轮子、车体和汽车底盘都是汽车的一部分,这些不同功能的部件聚合成为汽车这个整体。

(3)标识属性。对象所保存的信息称为它的属性。类的属性描述状态信息,在类的某个实例中,属性的值表示该对象的状态值。需要找出每个对象在目标系统中所需要的属性,并将属性安排在适当的位置,找出实例连接,最后再进行检查。应该给出每个属性的名字和描述,并指定该属性所受的特殊限制(如只读、属性值限定在某个范围之内等)。

(4)标识服务。对象收到消息后执行的操作称为对象提供的服务。它描述了系统需要执行的处理和功能。定义服务的目的是为了定义对象的行为和对象之间的通信。其具体步骤包括:

— 标识对象状态

— 标识必要的服务

— 标识消息连接

— 描述服务

可以用类似于流图的图形来表示服务。

(5)标识主题。为了更好地理解包含大量类和对象的概念模型,需要标识主题,即对模型进行划分,给出模型的整体框架,划分出层次结构。可以按照如下步骤来标识主题。

— 识别主题

— 对主题进行改进和细化

— 将主题加入到分析模型

主题是一个与应用相关的概念,而不是人为任意引出来的,主题层的工作有助于理解分析的结果。

6.3.5  优点

面向对象分析的主要有点有:

(1)加强了对问题域和系统责任的理解;

(2)改进与分析有关的各类人员之间的交流;

(3)对需求的变化具有较强的适应性;

(4)支持软件复用;

(5)贯穿软件生命周期全过程的一致性;

(6)实用性;

(7)有利于用户参与。

 

6.4  面向对象设计

面向对象设计的任务是对面向对象分析的结果作进一步的规范化整理,以便能够被面向对象编程直接接受。

6.4.1  概念

面向对象设计是一种软件设计方法,是一种工程化规范。这是毫无疑问的。面向对象设计的主要工作包括:

— 确定需要的类;

— 给每个类提供一组完整的操作;

— 明确地使用继承来表现共同点。

概括地说,面向对象设计就是“根据需求决定所需的类、类的操作,以及类之间关联的过程”。

从面向对象分析到面向对象设计是一个逐步扩充模型的过程。面向对象分析以实际问题为中心,可以不考虑与软件实现相关的任何问题,主要考虑“做什么”的问题;面向对象设计则是面向软件实现的实际开发活动,主要考虑“怎么做”的问题。

面向对象设计的目标是管理程序内部各部分的相互依赖。为了达到这个目标,面向对象设计要求将程序分成块,每个块的规模应该小到可以管理的程度,然后分别将各个块隐藏在接口(interface)的后面,让它们只通过接口相互交流。比如说,如果用面向对象设计的方法来设计一个客户端-服务器应用,那么服务器和客户端之间不应该有直接的依赖,而是应该让服务器的接口和客户端的接口相互依赖。

这种依赖关系的转换使得系统的各部分具有了可复用性。还是拿上面那个例子来说,客户端就不必依赖于特定的服务器,所以就可以复用到其他的环境下。如果要复用某一个程序块,只要实现必需的接口就行了。

面向对象设计是一种解决软件问题的设计范式(paradigm),一种抽象的范式。使用OOD这种设计范式,我们可以用对象来表现问题领域的实体,每个对象都有相应的状态和行为。面向对象设计是一种抽象的范式,抽象可以分成很多层次,从非常概括的到非常特殊的都有,而对象可能处于任何一个抽象层次上。另外,彼此不同但又互有关联的对象可以共同构成抽象:只要这些对象之间有相似性,就可以把它们当成同一类的对象来处理。

6.4.2  原则

面向对象设计的主要原则如下。

1.模块化

面向对象开发方法很自然地支持了把系统分解成模块的设计原则:对象就是模块。它是把数据结构和操作这些数据的方法紧密地结合在一起所构成的模块。

2.抽象

面向对象方法不仅支持过程抽象,而且支持数据抽象。

3.信息隐藏

在面向对象方法中,信息隐藏通过对象的封装性来实现。

4.低耦合

在面向对象方法中,对象是最基本的模块,因此,耦合主要指不同对象之间相互关联的紧密程度。低耦合是设计的一个重要标准,因为这有助于使得系统中某一部分的变化对其他部分的影响降到最低程度。

5.高内聚

— 操作内聚。

— 类内聚。

— 一般-具体内聚。

6.4.3  任务

面向对象设计的主要任务如下。

1.对象定义规格的求精

对于面向对象分析所抽象出来的对象、类,以及汇集的分析文档,面向对象设计需要有一个根据设计要求整理和求精的过程,使之更能符合面向对象编程的需要。这个整理和求精过程主要有两个方面:一是要根据面向对象的概念模型整理分析所确定的对象结构、属性、方法等内容,改正错误的内容,删去不必要和重复的内容等。二是进行分类整理,以便于下一步数据库设计和程序处理模块设计的需要。整理的方法主要是进行归类,对类、对象、属性、方法和结构、主题进行归类。

2.数据模型和数据库设计

数据模型的设计需要确定类、对象属性的内容、消息连接的方式、系统访问、数据模型的方法等。最后,每个对象实例的数据都必须落实到面向对象的库结构模型中。

3.优化

面向对象设计的优化设计过程是从另一个角度对分析结果和处理业务过程的整理归纳,优化包括对象和结构的优化、抽象、集成。

对象和结构的模块化表示为面向对象设计提供了一种范式,这种范式支持对类和结构的模块化。这种模块符合一般模块化所要求的所有特点,如信息隐蔽性好,内部聚合度强和模块之间耦合度弱等。集成化使得单个构件有机地结合在一起,相互支持。

6.4.4  阶段

面向对象设计分为两个阶段,即高层设计和低层设计。

高层设计阶段开发系统的结构,构造软件的总体模型。在这个阶段中,应该标识出在具体的计算机环境中进行问题求解所需要的概念,并增加一批需要的类,其中包括那些能使软件系统与外部世界进行交互的类。高层设计阶段的输出是适合应用软件要求的类、类之间的关系,以及应用子系统的视图规格说明。图6-13说明了面向对象设计导出的系统结构的大致形式。

在高层设计的过程中,应当使子系统的高层部件之间的通信量达到最小,把子系统中相互之间存在高度交互的类划分在同一组中。

低层设计集中于类的详细设计阶段。类设计的目标是形成单一概念的模型(即一个概念用一个独立的类来表示),而且设计的部件应该是可复用的和可靠的。在类的设计过程中需要采用信息隐蔽、高内聚、低耦合等设计原则。重复使用现有的类是面向对象的技术的主要优点之一。

图6-13  面向对象设计导出的系统结构

6.4.5  过程和步骤

Coad与Yourdon在设计阶段继续采用面向对象分析阶段中提到的5个层次(对象和类、结构、属性、服务和主题),这样有助于从分析到设计的自然过渡。根据Coad与Yourdon的面向对象设计方法,设计阶段的主要任务是利用这5个层次来建立系统的4个组成部分,即问题领域、用户界面、任务管理和数据管理。

1.问题领域

问题领域包括与我们所面对的应用问题直接相关的所有类和对象。实际上,在面向对象分析阶段就已经开始进行问题领域的分析。此时需要对它进行进一步的细化。面向对象分析得到了与应用有关的概念模型,面向对象设计应该对这个概念模型进行改进和增补。主要根据需求的变化来对面向对象分析阶段产生的模型中的类和对象、结构、属性和操作进行组合和分解,根据面向对象设计原则来增加必要的类、属性和关系。问题领域部分的设计包括:

— 复用设计

— 关联问题领域中的类

— 加入一般化的类以建立类间协议

— 调整继承的支持级别

— 改进性能

— 加入较低层的组件

2.用户界面

通常在面向对象分析阶段给出了所需的属性和操作,在面向对象设计阶段必须根据需求把交互的细节加入用户界面的设计中,包括有效的人机交互所必需的实际显示和输入。用户界面部分的设计主要由以下几个方面组成:

— 用户分类

— 描述人及其任务的脚本

— 设计命令层

— 设计详细的交互

— 继续扩展用户界面原型

— 设计人机交互类

— 根据图形用户界面进行设计任务管理部分的设计

3.任务管理

任务是进程的别称,是执行一系列活动的一段程序。当系统中有许多并发行为时,需要依照各个行为的协调和通信关系来划分各种任务,以简化并发行为的设计和编码。任务管理主要包括任务的选择和调整,它的工作包括:

— 识别事件驱动任务。

— 识别时钟驱动任务。

— 识别优先任务和关键任务。

— 识别任务之间的协调者。

— 对各个任务进行评审保证它能够满足选择任务的过程标准。

— 定义各个任务,说明它是什么任务、任务之间如何协调工作、如何通信。

4.数据管理

数据管理提供了在数据管理系统中存储和检索对象的基本结构,包括对永久性数据的访问和管理。数据管理的方法主要有三种,即文件管理、关系数据库管理,以及面向对象的数据库管理。数据管理设计包括:

— 数据存放设计。数据存放设计选择数据存放的方式(文件存放、关系数据库表格存放或面向对象的数据库存放)。

— 设计相应的操作。为每个需要存储的对象和类增加用于存储管理的属性和操作,在类和对象的定义中加以描述。

在每一个过程中,面向对象设计的基本操作步骤包括:

— 细化重组类。

— 细化和实现类间关系,明确其可见性。

— 增加属性,指定属性的类型与可见性。

— 分配职责,定义执行每个职责的方法。

— 对消息驱动的系统,明确消息传递方式。

— 利用设计模式进行局部设计。

— 画出详细的类图与序列图。

 

 

6.5  小结

—  UML是一种标准的建模语言。

— 常用的UML图包括用例图、类图、对象图、序列图、状态图、活动图、组件图和部署图。

— 对象建模技术是进行面向对象分析和设计的基础。

— 通过面向对象分析和设计,就能得出目标系统的对象、类以及它们之间关系的完整结构信息,为编写代码打好基础。

posted on 2009-11-24 14:44  冰云  阅读(1135)  评论(1编辑  收藏  举报