面向对象的RUP建模综述

[1前言]
  尽管我们在6个月的训练中曾清晰地描述和演练了过多次(UML课程),还是经常有学员抓着头皮来问软件工程的老师:大公司怎么做软件?想一想同样的问题是不是一样地困扰着跃跃欲试的你?那么请还是先看看这两张表格:

   说实话,至于2004年以后他们是不是这么干的我也不清楚,今年他们给我拜年时,仍然只是:“Happy New Year”,没告诉别的。
对于Borland和IBM来说已经在层出不穷的软件工程思想中涅槃了一回又一回。即便如此,即使是IBM仍然需要构建完整的软件工程标准体系。
当然国内所谓的大公司多数也这么干。只不过其没有巨头式的商业竞争背景。所以收集资料并整理了这份文档。如果你能有滋有味地读本文20遍,那么最起码面对面试官你就会侃得有滋有味,或者一不留神将其侃晕。
注意:不仅是因为IBM这么干(IBM并购了Rational),更是因为你是Java程序员,所以我们来探讨RUP。

[2软件分析与设计]
  在面向对象的开发领域,UML极大的促进了软件分析和设计的标准化进程。
你需要知道UML和Rational Rose(请再一次翻阅你的课本)以及由Rational 提供的Rational Unified Process软件工程体系。用RUP建立UML设计模型,可以使设计工作更高效,更有效。
  在生活和工作中,遇到问题时我们怎么办?很简单,我们会:
   1. 分析问题;
   2. 找出解决办法(可能会有几个备选方案);
   3. 着手解决问题。
  对于软件工程而言,这三个步骤可以理解为:
   1. 确定并分析需求;
   2. 根据需求进行设计;
   3. 根据设计进行实现(编码;测试;部署)。
  注意:分析和设计在大多数情况下是密不可分的。

[2.1分析和设计的必要性]
  早期的软件规模较小,参与人员很少,因此,大部分的设计工作是在个人头脑中进行的。那是一个崇尚天才的时代,早期的大部分软件/系统设计师都被称为天才设计师,那是对他们个人工作能力的赞美,也是因为对这种开发方式的质疑:一两个人就能完成一个复杂的软件系统(如操作系统)是不可思议的。
   随着软件系统的不断演化,现在的大部分应用系统已经不可能由一两个人单独完成了,取而代之的开发方式是多人协作。这个时代也有天才,这些天才大部分是能够清晰表达自己思想的人。
   多人协作方式下,分工是必然的。因此,根据个人能力、特长进行了不同的分工,其中一部分人分析问题,并提出解决方法,另一部分人根据解决办法进行实现。为了保证思想的延续和一致,解决办法形成书面文档。只有形成了可复述、可传递的表现形式时,才能称之为设计。

[2.2设计的一般过程]
  设计的过程,是一个将问题从原始的业务领域转移到计算机领域并找出有效的、可行的解决办法的过程。
因此,设计的目标是找到解决方法,而且这个解决方法还必须符合业务要求。这一点是需要注意的。
设计一般包含下列过程:
  1. 系统架构设计:根据业务需求和技术要求,设计出系统的架构,架构应当包括模式,机制,复用策略,实现结构(子系统结构)等。
  2. 子系统设计:定义子系统接口及子系统间协作关系。 定义子系统内部结构和依赖关系。
  3. 类设计:定义类的属性,方法,使用的设计模式和实现方法。
  应当注意的是,对于应用系统而言,过于详细的设计会给变更管理带来大量的工作,同时,针对于实现的详细设计应当由程序员来完成,其仅作为编写代码前的参考(你不是学习了I-P-O,并已经能用伪码来描述它了吗?)。

[2.3设计的一般原则]
  1.设计必须符合业务要求。这是最基本的原则。
  2.设计文档必须清晰,明确。并对设计的实现有指导作用。否则,很难保证设计与实现的一致性。
  3.开放性。软件的开放性是指软件本身对其他行业标准的支持能力。通过对标准的实现或支持,软件可以很容易的使用其它成熟软件产品来扩展其能力,或者支持其他产品的接入。开发性的设计必须在架构设计阶段完成。通常的标准都会提供对某种问题的标准解决方案(方法),它可以引导后续的设计工作。例如,在Web Application中的开发,应当遵循J2EE规范和其他行业标准如工作流,XML等等。
  4. 复用性。软件复用性是考量一个软件设计是否成功的重要因素。复用软件可以提高开发效率,减少缺陷。复用性是指软件可以在不同的(差异性)应用系统中重复使用的一种能力。一般的,通过几个方面进行复用性设计:
  a) 最小化差异。在设计之初应当与先考虑到不同系统间可能的差异的。并努力缩小差异,那么,这些差异就是软件被复用时的前提条件。
  b) 考虑不同层次的复用。完美的复用一般并不存在,因此,可以通过控制差异的级别,来完成不同层次的复用设计,如数据层,逻辑层,表现层等。
  c) 从流程角度屏蔽差异。某软件实现的功能具有固定的(或通用的)逻辑流程,那么可以总结并复用这一流程。
  5. 可扩展性。可扩展性是指软件可以在未来通过其它软件扩展其功能,这一点和开放性有些类似。设计可扩展的软件一般使用接口代替实现,并允许配置接口实现。与复用性类似的,该接口应当是稳定的。进行扩展性设计前应当明确定义软件的扩展点(接口),并描述清楚该扩展点的扩展模式。以便其它软件可以遵循这一设计实现新的功能。
  6. 兼容性设计。在对软件进行重新设计(扩展功能,移植等)时,应当考虑设计变化对已有系统的影响。最理想的结果是向下兼容,保证对已有系统没有影响。兼容性设计比较困难,但也是开发过程中不可避免的。

[3.RUP简介]
  Rational Unified Process是一种软件工程过程(Software Engineer Process )。它为开发团队提供了一个有效的方式来指派任务和职责。它的目的是确保在可预计的计划和预算范围内生产出满足用户需求的高质量的产品。(在田老师那里有它的拷贝)

上图描述RUP的总体架构。
RUP使用两个维度描述软件生命周期:
  1. 横坐标是时间线,展示了生命周期的概况。生命周期会分为4个阶段(Phase),每一阶段由多次迭代(Iteration)构成。
  2. 纵坐标是核心工作流(Discipline)。描述了每一组活动的分类情况。从图中我们可以看到,随着时间的变化,项目活动重点也随之发生变化。

[3.1 关键概念]
RUP定义了下列关键概念,并使用这些术语描述其活动:
  1. Discipline:核心工作流是一组相关活动的集合,对应整个项目过程中一项重要工作内容。将活动(activity)使用核心工作流组织起来,有助于理解整个项目的工作安排并可以避免繁琐的细节。如需求核心工作流包括分析问题,理解需求,定义系统,定义系统范围等活动。
  2. Workflow:工作流是一个活动序列,它最终会产生可见的有价值的结果。
  3. Role:角色定义了一个个体或一组(从事相同工作的)人的在软件开发团队中的行为和责任。角色并不等同于个体,同一个个体可以在一个项目中同时担任不同的角色。例如程序员负责编码,设计人员负责进行软件设计等。
  4. Activity:活动就是角色需要完成的工作。活动必须由明确的目的,结束时必须提供一个有意义的结果,否则无法衡量该活动的效果和质量。每一个活动一般分成准备,实施,复查三个步骤,这有助于有效的完成该活动。
  5. Artifact:制品是一个活动的工作成果。角色使用制品以完成活动,或者在活动过程中生成制品。生成制品是某些角色的职责,并用来为其他角色提供信息。制品可以有多种形式。如程序员生成的制品是源代码和可执行程序。需求人员生成需求文档。设计人员生成设计模型。

[3.2阶段划分]
  RUP按时间分解为四个阶段,每一个阶段都包含一个Milestone。每阶段结束后评估该阶段是否达成了Milestone的目标。
  各阶段的时间和整体效果是不同的,这依赖于不同项目情况。通常在一个中型项目开始时可以这样估算个阶段的时间和效果:

下表列出了各阶段的目标和主要活动:


[3.3最佳实践方案]
  RUP总结了近年来的开发过程和开发理念,提出下述最佳实践方案:
  1. 采用迭代方式递进开发。每次迭代完成都会发布一个可执行版本。迭代的目的是尽早发现风险,以便有效的降低风险。迭代方式允许产品持续改进。迭代方式主要由下列优点:
   a) 允许变更需求。因为需求总会发生变化,正确的做法不是回避变更,而是处理变更带来的一系列问题。
   b) 逐步集成组件。避免将所有的集成工作放在最后,并寄希望一次成功,分阶段集成组件时,每一次的工作量都要小得多。
   c) 及早降低风险。及早发现风险是降低风险的有效手段。
   d) 有助于团队学习和提高。每一次迭代都是一个简短而完整的开发周期,通过每一次迭代,团队成员有机会熟悉工作方法、技能,并不断提高。
   e) 提高复用性。在排除未知的细节和可预知的细节之后,为初始迭代进行的设计一般具有加高的通用性。
   f) 生成性能更健壮的产品。每一次迭代都带给开发人员一个修改错误的机会。持续改进中产品性能也会持续改进。
  2. 管理需求。需求管理包括下列内容:
   a) 获得,组织系统需求并形成文档。
   b) 在项目开发小组与客户舰对需求变更达成一致并维护这些变更。
  需求总会发生变化。因为有些需求很难表达。有是客户也不清楚自己的需求。在系统的迭代进程中,某些需求会逐渐清晰,有时会衍生出全新的需求。这些都需要付出努力去维护。RUP建议使用Use Case组织、描述需求。
  3. 持续检验质量。RUP 中使用,质量被定义为:
   a) 满足或超出认定的一组需求,并
   b) 使用经过认可的测量方法和标准来评估,还
   c) 使用认定的流程来生产。
  必须在整个生命周期的每一阶段,活动中检验质量,这也是活动三个步骤中复查的作用。

 

[3.4 用例驱动的软件过程]
  RUP使用用例描述、管理系统需求和需求变更。一切功能性需求源于用例。
  与长长的需求列表不同,用例描述了一个个如何使用系统的故事,对于重要需求,提供了一个用户角度的理解。这种描述方法更全面,更具有连续性。
  传统的面向对象系统模型通常难于讲清楚系统是如何工作的,这是因为系统由对象构成,缺乏面向过程系统模型中的贯穿整个系统的流程。RUP中,用例描述系统工作流程。用例不属传统面向对象技术的一部分,但绝对是重要的部分。
  RUP使用用例驱动方法(use-case driven approach),这意味着用例定义了整个系统的基础内容。
用例在不同的核心工作流中都扮演着重要角色。
 1. 在业务建模过程中,用例的概念可以用来描述业务过程,这是它被称为”Business Use Case”。
 2. 在需求工作过程中,用例是该过程的成果。这些用例一起构成了客户和开发人员必须接受并达成一致的系统基本需求。
 3. 在分析设计阶段,用例在Design Model中被实现。为每一个用例创建Use Case Realization以描述如何用对象交互来实现用例。
 4. 在实现过程中,Design Model将作为实现规范。用例将使用设计类实现。
 5. 在测试过程中,用例可以认为是测试用例和测试流程的基础,通过执行每一个用例来验证系统。
 6. 在部署阶段,用例构成了用户手册的基础。

[4. RUP软件设计过程]
  本节我们将介绍RUP软件设计过程。讨论的重点是RUP Framework的架构和此过程中的概念和方法。

[4.1 RUP Framework组织方式]
  使用Rose建立一个新模型时,可以选择进行设计的备选框架,选择Rational Unified Process 框架就建立了一个RUP Framework模型。如果没有提示选择备选框架,可以在Add-Ins->AddIn manager 中选择Framework Wizard。
RUP使用下列视图组织UML模型:
  Use Cases View:用例视图中使用Use Cases Diagram,Use Case,Actor描述系统需求。这其中应当使用用例描述全部功能性需求。并提供附加文档描述非功能性需求。这一部分工作对应需求和需求分析核心工作流。
  Logic View:逻辑视图描述如何实现Use Case View中的各个用例。一般包含分析模型,设计模型以对应的分析设计核心工作流。逻辑视图使用类图,用例实现,时序图,协作图,活动图和状态图描述对象间关系和对象行为,并说明如何使用这些对象实现系统需求。
  Component View:组件视图描述可执行组件的结构。
  Deployment View:部署视图,描述系统的网络硬件结构,并描述在不同服务器上的进程,线程分布情况。

[4.2 源于Use Case]
  前面提到,RUP使用用例描述、管理系统需求和需求变更。一切需求源于Use Case。RUP是由用例驱动的过程。
RUP在Use Cases View中定义、描述用例,并在Logic View中实现它。
用例包含下列关系:
 1. Association:用于执行者和用例之间,表示执行者与用例会发生通信。这也是用例和执行者间的唯一关系。
 2. Extend:从用例A到用例B之间的扩展关系表示B(在指定的条件下)会增加A定义的行为。该行为将插入到B中定义的相应扩展点上。
 3. Generalization:从用例A到用例B间的泛化关系表示用例A使用例B的一个特例。
 4. Include:从用例A到用例B的包含关系表示用例B将包含用例A定义的行为。行为将插入到B中定义的位置。
利用用例间关系可以有效的表达系统需求,更好的组织用例。

[4.3 使用Use Case组织需求]
  RUP的Use Cases View包括一个Use-Case Model和一个Business Use-Case Model。Use-Case Model中包含支持系统需求中业务过程的用例。Business Use-Case Model中包含业务活动,使用活动图或用例图进行描述,这部分内容的目的是为Use-Case Model提供分析的基础。可以这样理解这两个模型:
 l 业务用例模型视使用业务术语描述系统需求,它将系统需求通过一个个客户易于理解的方式表达出来。
 2 用例模型是对业务用例模型的抽象和归纳,它更利于开发人员理解。
用例模型中包括Actor和Use Cases两个Package。分别定义了系统中的执行者和用例。
  用例包中每一个用例使用单独的Package管理。所有仅与该用例有关联(包含,扩展,泛化)的其他用例都应包含在一个Package中。
  每一个用例包中包含一个Use Cases Diagram描述用例与执行者和其他用例的关系。
  对于每一个用例,视其复杂程度可以使用活动图或状态图描述其流程。
  应当为每一个用例编写一份用例说明文档。文档格式参见sep.cssweb.com.cn。同样的,仅与该用例相关联的其他用例也可包含在该文档中。
  Rational建议使用编号管理用例,以方便引用和跟踪。

[4.3.1 找出关键用例(需求)]
  为了更好的安排迭代计划,RUP要求找出系统中的关键用例(Architecturally Significant Use Cases)。这些用例可能是优先级别高的用例,或者是风险高的用例,或者会影响到设计结构的用例。
这体现了RUP中的另一个驱动因素:

[4.3.2 使用Use Case View的提示]
 1. Actor间的关系仅能使用泛化。使用泛化是完成执行者(一般对应着系统用户)抽象和组织的唯一手段。
 2. 注意用例间的关系,使用这些关系一般都是为了复用用例。Extend是指有条件的包含;Include是无条件的包含;Generalization是部分复用。
 3. 描述用例时应当着重于动词和名词,一般名词会对应着实体对象或对象属性。如:账户信息,在后面的设计中可能会变成一个对象,而动词如存款可能对应一个方法。
 4. 使用活动图来描述用例流程会使用例的流程更易于理解,尤其在一个用例就有多各分支的情况下。
 5. 活动图中可以有效的捕捉对象,如果动作由不同的对象完成或者是对不同的对象进行的,可以使用分隔线(Swim lane)讲这些对象分开,这可以作为设计中时序图的基础。

[4.4 设计软件架构]
  软件架构是一个易于理解的概念,很多软件设计师依靠直觉和经验进行设计,但并不那么容易准确的表达。在RUP中,软件系统架构是系统中关键组件的组织形式或结构,这些组件可能由其他组件组成并通过接口进行通信。软件系统架构描述在Software Architecture Document中。
软件架构应当着重描述下列内容:
 1. 软件模型的组织结构。例如层次结构。
 2. 基本元素,如关键用例,主要类,通用机制等。
 3. 一些关键场景(过程)描述以展示整个系统的主要控制流程。
 4. 服务,以便分解模块,可选特性和产品样貌。
软件架构的本质是整个系统设计的抽象和简化,过滤掉一些细节可以是整个系统的重要特性更加突出。下面列出了部分重要特性:
 1. 系统的演进方法,描述如何转入开发周期的下一阶段。
 2. 架构的重用。
 3. 对系统质量的评估,如性能,可移植能力,安全性等。
 4. 对开发小组工作的评估。
 5. 使用其它外部组件(外购或其他途径)的决策。
如前所述,软件架构文档应当作为指导设计人员进行进一步组件设计的指南。设计人员必须理解软件架构文档中提出的系统结构、子系统间的接口约束,并参考或遵循分析机制和模式进行组件设计。

[4.4.1 系统分层]
  系统分层是一个有序的功能性分组。一般的,与应用功能细节相关的部分定义在上层;包含整个应用领域的功能部分定义在中层;与部署环境相关的部分定义在底层。
  层次的数量和组合方式依赖于应用的复杂性和解决方案架构。简单的业务系统可能只有一层。包含更复杂业务逻辑的应用系统可能会在业务逻辑部分分成几个层次。依赖于中间件的应用系统可能会保留中间件相关的层次,而专注于业务层次。
  基于J2EE标准的Web应用系统使用了J2EE服务器作为中间件,因此,我们可以将精力集中在业务逻辑上,这种系统的分层主要集中在业务逻辑上。

[4.4.2 如何分层]
  层次将子系统划分为不同的集合,并约束了子系统间的相互依赖关系,这使得子系统间的耦合更松散,更容易维护。
子系统分组(分层)的标准应当遵循下列模式:
 1. 可见性(Visibility):子系统应当仅依赖于同一层次或下一层次中的其他子系统。因为分层是有序的。其依赖关系必须从顶至底。
 2. 变化率/稳定性(Volatility):
  a) 最高层应当包含那些容易随着用户需求变化而发生较大改变的部分子系统。
  b) 最底层营包含那些随部署/实现平台环境变化而改变的部分子系统。
  c) 中间层次包含那些具有关泛适用性的(业务或部署环境)子系统。
  d) 在这中间添加其他层次以组织整个设计模型。
 3. 一般性(Generality):抽象的模型元素一般放置在较低的层次。如果没有实现的特殊性,可以转移到中间层。
 4. 层次数量:小型系统使用三个层次就足够了。更复杂的系统一般使用5-7层。十层以上的系统一般会带来极大的复杂性,可能会抵消分层的好处。

[4.4.3 使用子系统]
  子系统(Subsystem)一般是系统中可独立的部分,它通常提供完备的一组功能,与系统的其他部分仅有很少的交互。子系统用来包装其他子系统和package,类。
通常的子系统组织模式如下:
 1. 人员组织结构:有时子系统的结构和实际的业务组织结构一致的(例如按照部门组织)。这一模式通常在设计出其应用,因为企业模型具有严格的有组织的结构划分。一般这种组织模式仅用于最顶层。但应当注意的是:
  a) 一般是一个比较容易进行得的良好的开端。
  b) 但由于人员组织结构不稳定,因此可能在后期带来麻烦。
 2. 以开发人员能力或经验为依据:子系统也可以出于在开发团队中分配职责的目的组织。这种模式一般应用于中层或底层,并会考虑其技术因素与相关的小组(或个人)联系起来。
 3. 系统分布情况为依据:每一个层次可能都会被水平的划分为物理分开的不同子系统。
  a) 这种模式有助于突出系统间的通信问题。
  b) 这种模式不能很好的适应系统重大变化。
 4. 保密考虑:出于保密、版权等考虑而进行子系统划分。这种情况一般无法有效的控制和变更。

[4.4.4 分析机制]
  分析机制是对常见问题的一般解决模式,通常表现为结构模式和行为模式或这两者兼备。分析机制有助于在分析过程中降低复杂度。良好的模式能够引导设计人员走出功能或行为细节,直接获取有价值的,经过验证的设计结果。
分析机制为设计人员提供了分析问题的角度,并提供了备选的解决方案。分析机制一般应用在中层或底层。
常见的分析机制如下:
 1. Persistency:对于每一个具有持续性的类(及其实例) ,一般需要从下列几方面考虑:
  ·Granularity(粒度),对象大小范围。
  · Volume(容量),对象数量。
  · Duration(持续时间),对象一般需要保持多少时间。
  · Retrieval mechanism(恢复机制),如何唯一确定一个对象并恢复它。
  ·Update frequency(更新频度),对象是经常更新还是很少更新,更新是永久的吗?
  · Reliability(可靠性),对象是否需要在系统异常的情况下保证其数据的正确和完整。
 2. Synchronization:进程控制和同步机制,不同的进程访问同一资源时,可能需要进行同步控制:
  · IPC(进程间通信),使用何种手段进行通信。
  · Protocol(协议),备选择的通信协议。
  · Access frequency(访问频度),对竞争资源的访问频度。
  · Volume(容量),竞争进程的数量,两个和两个以上的进程将采取不同的策略。
  · Duration of monopolization (独占时间),各竞争进程对资源的独占时间。
  · Reliability(可靠性),独占资源过程中的系统崩溃状态是否需要考虑以避免其他竞争进程死锁。
 3. Memory Management:对于大量对象的内存占用情况进行管理。
  · Memory reclaim(内存回收),Java自动回收内存,而其他的语言可能需要编码控制。
  · Size of Memory (内存大小),系统可用内存的大小和系统对象规模进行比较。
  · Cost of load/unload(对象装卸代价),对象装载和卸载的代价。
  · 对象使用率,一般的80/20法则可以作为评估的参考。
  · Reliability(可靠性),当内存耗尽时的应对策略。
 4. Security:安全机制。
  · Protocol and algorithm:安全对应的协议和算法。
  · System Structure:引入安全机制后对系统结构的影响。
  ·Granularity:需要进行安全管理的对象层次。
 5. Error reporting:错误处理、报告。
  · Language Feature:错误捕捉机制与使用的编程语言有很大关系。
  · Representation:如何表示错误:使用状态码或者异常?
  · Persistency:同样需要考虑错误结果的持续性。

[4.5 用例实现]
  用例实现(Use case Realizations)是连接Use Case和Design Class的桥梁,同时也是验证设计的手段。
在分析过程中,设计人员可以提取对象,那么,描述对象间如何协作实现业务需求可以使用用例实现。
  每一个用例实现都对应着一个(或多个)用例,相反的,每一个用例必须有一个用例实现与之相对应。基于用例的需求管理在这时体现出优点:只要确保每一个用例均被实现,就不会有功能性需求的遗漏。
  此过程中,还应尽量寻找与用例相关的非功能性需求如性能,UI要求等,以避免遗漏。
  用例实现一般使用类图描述与该实现直接相关的类间的关系。使用一个或多个时序图描述用例中的流程。一般的,每一个异常或可选流程,都应当对应一个时序图。

[4.6.1 创建初始设计类]
  一般的,在第一次迭代寻找并定义类的行为,这一步骤通过初始用例实现完成。
通过分析类的类型(boundary,entity,control),可以得出下列设计方法:
  ·设计边界类:一个基本原则是每一个窗口,表单(如JSP页面)或其他用于交互的类都是一个边界类。因此,可以得出结论:边界类一般出现在较高的层次中。
边界类的设计一般取决于用户界面的开发工具,在一些开发环境中,使用开发工具可以直接创建这些边界类。
边界类一般单独组织在一个子系统中,在边界类的设计中应当包含该类对应的UI样式。
对于Java Web Application中的边界类一般是JSP,JSP可以定义在一个层(如:view)中,并分成多个子系统按照JSP的目录结构进行管理。
  ·设计实体类:实体类表现为被操作的信息单元。实体对象通常是被动的,持久的。实体类一般需要利用Persistency机制进行分析。基于数据库的Persistency机制将在数据库设计一章中介绍。处于实现角度考虑,有时会将一个对象拆分成几个对象。
  ·设计控制类:一个控制对象管理用例的流程并与此相对应的一些行为。控制类封装那些与UI或数据库设计没有显著关联的逻辑,这些逻辑也被称为应用逻辑或业务逻辑。
基于此,设计控制类是必须考虑下列问题:
  · 复杂性:简单的控制或行为可以由边界类或实体类处理。随着应用复杂程度的提高,这种方式的缺陷就会暴露出来:
    ·用例对应的行为被包装在UI中,很难改变。
    ·同一个UI不能很容易的用于其他用例实现。
    ·UI附加了很多功能,这将降低它的性能。
    ·实体对象可能会与用例的特殊行为联系在一起,降低了通用性。
为了避免上述问题的发生,控制类可以考虑仅提供与流程相关的行为。
  · 变化概率:如果改变流程的可能性较低或则代价较小,增加控制类带来的额外开销和复杂性有些得不偿失。
  · 分布和性能:如果需要在不同节点或进程中运行程序的各个部分,那么对于设计模型中的元素也需要进行特殊设计。特殊设计通常通过从边界类和实体类中抽取分布式行为和控制对象的方法完成。这样,边界类仅提供纯粹的UI服务,实体类仅提供纯粹的数据服务,其他的服务由控制类提供。
  · 事务管理:管理事务是一个经典问题。通常是应一个独立的Transaction Manager处理这一问题。

[4.6.2 确定持久类]
  需要将状态保存在永久媒介上发的类被称为持久(Persistent)类。持久类可能又有一部分时例是不需要永久保存的。一个类被称为持久类仅仅因为它的部分实例需要永久保存。
  确定一个持久类之后,需要采用Persistency机制进行进一步的设计。如果使用数据库机制,就需要在数据库设计时将该类映射到数据库中。

[4.6.3 定义操作]
 以下方法可以有效的确定类的操作(Operations):
  · 研究每一个类的职责,并为每一个职责创建一个操作。
  · 研究用例实现中类的参与情况来了解用例实现是如何使用这些操作的。
  · 研究用例的特殊需求,确保没有遗漏其中的包含的需求。
 操作应当能够支持/取代时序图中的全部消息,每一个消息都是类需要实现的行为。
 用例实现并不能提供定义操作的全部信息,可以考虑下列内容以定义剩余的操作:
  · 有没有提供其他的初始化对象的方法?
  · 是否需要检查一个类的两个实例是否相等?
  · 是否需要建立一个实例的拷贝(clone)?
  · 该类实现的机制是否需要定义其他的操作?
 最后,不需要定义Get和Set方法。这些方法一般通过代码生成工具自动生成。

[4.6.5 定义依赖关系]
  当用例中两个对象需要通信时,就说明两个类之间存在依赖关系。
  依赖关系是一种临时关系,它被限制在通讯发生的时段和条件中。与关联(Associations)不同,关联是一种静态的结构关系,将在下一节介绍它。
  依赖关系可以用作子系统接口设计的依据,并可采用占位符(placeholder)的方法进行迭代开发。

[4.6.7 Role]
   在关联线的结束部分被称为一个角色。使用它可以描述关联对象在关联中的作用。每一个角色都应当有一个名字,同一个类的角色名称不能相同。
  关联名称与角色名称是互斥的,不能同时存在。角色名称更能准确的表示关联的含义。

[4.6.9 Navigability]
  Navigability表示可以从关联类查找到它的目标类。它可能通过直接对象引用,对象数组引用,Hash table或其它的手段实现。Navigability使用一个箭头表述。

[4.6.10 Association Classes]
  关联类是具有类属性的关联。关联类用来描述建立关联关系后需要附加的属性或方法。

   上图中定义了关联类Appraisal,该类描述manager与staff发生关联时,需要附加的数据。Employee类定义了员工,其中,Manager可以管理一个staff,因此,两者间定义了一个Self-Association,当这种关联建立后,会有一个Appraisal类来描述这种关联关系的数据,如:其实日期和终止日期。

[4.6.11 Aggregation]
   聚合是一种组合关联,它用来描述对象间的整体与局部的构成关系。
   现实生活中有许多聚合的例子,如:计算机由输入设备,输出设备,内存等部分组成。
聚合与关联之间存在不同,聚合必须是很强的组合关系。而关联则松散的多。可以这样考虑:如果A必须包含B的话,那么一般是聚合关系。

[4.7 数据库设计]
   在Rational Rose中,可以使用Data Modeler设计数据库结构。在Design Model中选择tools->Data Modeler->Add Schema创建一个数据库Schema,当然也可以使用Reverse Engineer从已建好的数据库中将数据库结构导入模型。
在Schema中可以建立表,视图,以及表间的关联关系。
  最后,使用Forward Engineer可以建立脚本,或直接在数据库中创建表。

[5. 后记]
  设计的目的是要搞清和澄清事实。
  如果事实很清楚还用设计吗?那要看是你一个人清楚还是大家都清楚?我想即使是大家都清楚也还是需要一套标准的符号来进行必要的交流。
  一个良好的设计首先要易于理解,进行软件设计是为了简化问题而不是把问题变得更复杂,设计不是数据结构、算法和设计模式的简单堆砌,更没有必要为
  了套用某种模式或展示自己的才华而使用复杂的,充满冷僻术语的设计。即使使用了某种算法或模式,也必须保证编码人员能够理解这种算法和模式。
  一个良好的设计应当体现需求,并最终满足需求。为了设计结构的优美,而去牺牲或修改一些需求,这么干是愚蠢的。
毫无疑问,软件分析和设计工作需要大量知识的积累,对于这里的学员,尤其是那些零起步的学员对本文你能理解40%就足够了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值