《面向对象的设计与技术第四章.ppt》由会员分享,可在线阅读,更多相关《面向对象的设计与技术第四章.ppt(141页珍藏版)》请在三一办公上搜索。
1、1,面向对象的设计与技术,杨文川北京邮电大学2007年2月,(OOD提高篇),2,面向对象的设计与技术,第四部分 设计(Design),3,第十四讲 设计工作流,面向对象的设计与技术,4,14.1设计工作流,设计工作流是在细化阶段的最后部分和构造阶段的前半部分的主要建模活动,将分析模型转变为设计模型。,需求,分析,设计,实现,测试,初步迭代,I1 I2,In In+1,Im Im+1,初始,细化,构造,移交,管理,配置,5,分析模型和设计模型间的区别,UP推荐,应该由同一个团队负责在从需求到分析和设计(最终到实现)来获取制品(例如用例),而不是采用一个分析师团队和一个独立的设计师团队。UP是围
2、绕可交付的制品和里程碑来组织团队的,而不是围绕特定的任务来组织团队的。,6,14.2设计工作流焦点,在分析中,焦点是创建系统的逻辑模型,该模型捕获系统为满足用户需求而必须提供的功能“作什么”。设计的目的是说明如何才能完全实现这个功能“如何作”。在设计中,OO设计师决定战略性设计问题,诸如对象持久性和分布,并且相应地创建设计模型。项目经理和设计师也应该制定政策以处理战术性设计问题。,7,14.3设计制品元模型,接口是设计中很重要的构架角色,需要花很多时间来寻找共建模关键接口。分析模型和设计模型之间存在简单的trace关系。设计模型建立在分析模型的基础之上,也可以看做是分析模型的精化和细化,8,例
3、子,一个包含许多设计子系统的设计系统,需要维护两个模型吗?,理想世界中,系统将具有单一模型,CASE工具能够给出那个模型的分析视图或者设计视图,实际是:。,10,分析视图的价值,分析视图提供系统的“大场景”。分析视图可能只包括在详细设计视图中的1%到10%的类,它的价值在于:介绍新人加入项目在交付几个月或几年后重新理解系统。理解系统是怎样满足客户需求以及提供可跟踪性。计划维护和增强。理解系统的逻辑构架。外包系统的构造。如果需要做以上的任何一项,那么绝对需要保留分析视图。,11,采用何种策略?,是否需要分析视图关键在于项目大小。如果系统庞大、复杂或是战略性的,或者具有很长项目规划生存期就应该保留
4、分析视图(选择策略3和策略4)。但需要考虑分析模型和设计模型步调不一致,你的项目真能接受吗?如果系统比较小(少于200个设计类),设计模型本身小得可以理解,如果系统不是战略性的或只有很短的规划生存期,独立的分析模型也就不需要了。因此只能在策略1和策略2之间选择了,对于中型系统来说,起着决定性因素的是UML的CASE工具的能力。有些CASE工具维护着单一的底层模型,并允许通过过滤和信息隐藏设法重新从设计模型获得“分析”视图。方案需要综合考虑。,12,14.4设计工作流细节,设计中主要参与者有构架设计师、用例工程师和组件工程师。,13,14.5制品,设计模型是分析模型的细化,设计模型添加了详细信息
5、和特定技术的解决方案。所有的属性和操作(包括返回值类型和参数列表)必须完整。设计模型由下列各项组成:设计子系统。设计类。接口。用例实现(设计)。部署图。接口是在设计中产生的关键制品之一。,14,14.4设计工作流细节,分析类是系统中类的高级概念视图,可以被分解成一个或多个接口或者设计类。当进行设计(物理建模)时,这些概念上的类需要被实现成一个或多个物理的设计类和/或接口。,15,小结,本讲介绍设计工作流,关于确定分析模型中说明的功能将如何被实现。设计工作流是在细化阶段最后部分和构造阶段前半部分的主要建模活动。设计模型包括:一个设计系统和若干设计子系统,用例实现(设计),接口,设计类,初步的部署
6、图。相互之间存在跟踪关系的有:设计模型与分析模型,设计系统与分析系统,一个或多个设计子系统与一个分析包。需要分别维护分析模型和设计模型的系统是:庞大的,复杂的,战略性的,受经常变更所支配的,期望长期运行的和外包的。,16,17,第十五讲 设计类,面向对象的设计与技术,18,15.1什么是设计类,设计类是已经完成了规格说明并且达到能够被实现程度的类。在分析中,类来源于问题域,是一组描述你试图去解决问题的需求,以作为分析类的来源。设计类来自两个方面:通过分析类的精化得到的问题域,这里的精化包括添加实现细节。解域它是实用类库和可复用组件的领域。,19,15.2 设计类,分析是关于建模系统应当做什么,
7、设计就是关于建模那些行为如何被实现。分析类是非常高级的抽象,操作集合只是捕获了类关键服务的骨干。在将分析类精化成设计类时就必须全面说明所有的操作和属性,通常会发现类太大了。如果发生这种情况,就应法将它分解成两个或者更多个类。应当记住,你所要设计的类是一些能真正做好一两件事情的小的、自含的而且内聚的单元。,20,15.3设计类剖析,在设计中必须准确地说明类是如何履行它们的职责,必须完成以下事情:完整的属性集合,包括详细说明的名称、类型、可视性和一些默认值(可选的)。将分析类指定的操作转化成一个或多个方法的完整集合。,21,15.4形式良好的设计类,一个形式良好的设计类应具备四个基本特征:完整的和
8、充分的。原始的。高内聚。低耦合。设计类将会被交给程序员去编写实际的源代码,也可以在CASE工具支持的情况下由模型自身直接生成代码。设计类需要被完整地说明,规格说明过程部分决定了这个类是不是“形式良好”。,22,完整性和充分性,完整性就是要提供给类客户他们可能预期的所有功能,满足客户所有合理的期望。充分性就是要保证类的所有方法注重实现隐藏在类背后的意图,恰好包含所需要的方法集合并且没有多余的方法。完整性和充分性的金科玉律是:类只做用户期望它们做的不多也不少。,23,原始性,方法应当设计成提供单一的、原始的原子服务。类不应提供多种方法做同样一件事情,这样容易使类客户混淆,并且会导致维护负担和一致性
9、的问题。目标是:应当提供尽可能小而简单的方法集合,24,高内聚,每个类都应当创建唯一的抽象概念模型,并且具有支持类意图的方法集合这就叫做内聚性。内聚性是类最理想的特征之一,内聚的类通常容易理解、复用和维护。内聚的类具有一小组紧密联系的职责。每个方法、属性和类关联都被特别地设计用以实现这个小而专注的职责集合。,25,低耦合,特定的类应当仅与那些可以帮助它实现职责的类产生关联,并只关联那些存在真正语义链接的类这就是低耦合性。耦合是对象建模中最可怕的敌人,所以必须真正地事先尽量限制类间的关系,目的是尽可能最小化耦合。高度耦合的对象模型会导致系统不可理解和不可维护Spaghetti Code,26,1
10、5.5继承,在分析中只在那些相互之间存在清晰明确的is a关系的设计类间才使用继承。但在设计中你可以选择使用继承来复用源代码。这是不同的策略,因为你正在使用继承来使子类的实现更加灵活和轻松,而不是使用继承表示父类和子类之间的业务关系。,27,继承可能带来的问题,继承是OO中产生多态的机制,但也导致一些问题:在两个或多个类之间可能产生的耦合中,它是最强的耦合形式。类层次中的封装是脆弱的,基类改动会直接波及子类变化。它是一种非常牢固的关系类型,在运行时候是固定的,这就意味着它是类之间的关系中最不易改变的一种类型。,28,聚合与继承,使用聚合取代继承可以得到正确的语义,得到了更加灵活并且语义正确的模
11、型。一个重要的通用原则子类通常应该是描绘“is kind of”。而不是描绘“Is role played by”。,例子,考虑:John由Programmer提升为Manager,30,多重继承,从多于一个的父类继承实现,这就是多重继承。多重继承的几个要点如下:多重继承涉及的所有父类在语义上必须正交(相互间成直角)。is kind of和可替换性原则必须适用于子类和它的所有超类之间。典型地,超类应当没有共同的父类,否则,继承层次就会形成循环。,31,例子,有效使用多重继承的通常方法是Mixin类,32,继承与接口实现,当你关心从超类继承一些实现细节(方法、属性和关联)时,只需要使用继承。这是
12、一种复用方式,事实上在OO的早期它被当做一种主要的复用机制。到今天,设计师们已经认识到有时侯继承施加了难以接受的约束并且在某种程度上已经偏移了它的用途。当希望定义契约而不关心继承实现细节时,接口实现是很有用的。因为在接口实现中并不真正继承任何事物,所以在某些方面它比继承更加灵活和健壮。,33,区别,继承和接口实现具有一些共性,都允许你定义子类必须实现的契约(方法集合)。但这两种技术有着非常不同的语义和用途。从继承中可以得到两件事物:接口基类的公共方法。实现基类的属性、关联、保护方法和私有方法。从接口实现仅得到一件事物:接口一组没有实现的公共操作。,34,15.6模板,模板允许参数化类型,这意味
13、着,你可以根据占位符或参数定义类,而不去说明属性、方法返回值和方法参数的实际类型。通过用实际值代替占位符就可以创建新的类。可以通过使用bind构造型化的依赖关系来实例化模板这被称为显式绑定。,35,例子,36,15.7嵌套类,嵌套类声明在它的外层类的名字空间中,只能通过那个外层类或者外层类的对象对它进行访问。只有外层类或者外层类的对象才能创建和使用嵌套类的实例。,37,例子,窗口类HelloFrame从父类Frame类中继承了基本的窗口行为。HelloFrame具有名为MouseMonitor的嵌套类,嵌套类从它的父类MouseAdapter继承了处理鼠标事件的能力。,38,小结,本讲介绍设计
14、类设计类是规格说明已经完成并且达到能够被实现程度的类,有两个来源:问题域和解域设计类具有完整的规格说明:属性集合和方法:形式良好的设计类展现特定特征:完整性,充分性,原始性,高内聚,低耦合只有在两个设计类之间存在清晰明确的“is a”关系或为了复用代码时才使用继承多重继承允许一个类有多个父类。注意继承与接口实现的区别联系模板允许你“参数化”类型嵌套类是在一个类内部定义另一个类,39,40,第十六讲 精化分析关系,面向对象的设计与技术,41,16.1设计关系,当转向设计时,你必须将分析类之间的关系精化成设计类之间的关系。分析中捕获的许多关系不能像它们显示的那样直接地实现,但是又必须做到这一点。例
15、如,没有一种普遍使用的OO编程语言能直接支持双向关联、关联类或者多对多关联。为了创建一个设计模型,你必须说明如何实现这些关联。,42,16.2精化设计关系,精化设计关联包括几个过程:在恰当的地方将关联精化成聚合或是组合关系。实现关联类。实现一对多关联。实现多对多关联。实现双向关联。所有的设计关联必须具有:导航性。两端的多重性。所有设计关联应至少在目标端有一个角色名称。,43,16.3聚合和组合,在设计中,可以将关联关系精化成聚合或组合关系。聚合这是一种松散的对象间关系计算机和它的外围设备就是一例。组合这是一种非常强的对象间关系树和它的树叶之间的关系。,44,16.4聚合语义,聚合是整体一部分关
16、系的一种,一个对象(整体)使用另一个对象(部分)的服务。聚合语义总结如下:聚合有时能够不依赖部分而存在,有时又不能。部分可以独立于聚合而存在。如果有一些部分遗失,聚合会给人一种不完整的感觉。部分的所有权可以由几个聚合来共享。,45,聚合的特性,聚合是可传递的。聚合是非对称的。这意味着对象永远不会成为它自身的部分。,46,16.5组合,组合是一种更强形式的整体部分聚合关系,并且具有传递性和非对称性。聚合和组合的关键区别在于,在组合中部分脱离了整体就不能独立存在。此外,组合中的每个部分属于一个整体,也只能属于一个整体,而在聚合中一个部分可以由几个整体共享。,47,组合语义,组合的语义总结如下:部分
17、在某一时刻仅仅只能属于一个组成。组成唯一他负责处理它的所有部分,这意味着负责它们的创建和销毁。倘若对于部分的职责由其他的对象来承担的话,组成也就可以放松这些职责。如果一个组成销毁的话,它必须将它所有的部分销毁,或者把负责处理它们的权利交给其他的对象。注意:因为组合唯一地负责处理和安排它的所有部分的生命期,所以当创建一个组成的时候,组成对象也就创建了它的部分。类似地,当你销毁一个组成时,组成必须将它所有的部分全部销毁,或者安排另外一个组合来接受它们。,48,组合与属性,组合语义和属性的语义非常相似。两者都具有由它们的主人控制的生命期;脱离了它们的主人就不能独立存在。事实上,属性正好相当于组成类和
18、该属性的类之间的组合关系。那为什么我们要用两种方法表达相同的事物呢?这有两个原因。属性可以是原始数据类型。如int和double像Time、Date和String这些有特定功能的类被普遍使用。比较好的方法是把这样的类建模成属性。底线是:如果你有原始类型或者实用类,就应当考虑使用属性而不是组成关系。,49,16.6如何精化分析关系,按照下面的步骤进行:如果缺少的话,添加多重性和角色名称到关联。确定关联的哪一端是整体,哪一端是部分。考虑整体一端的多重性,如果正好是1,那么可能能够使用组合;否则,就必须使用聚合。添加从整体到部分的导航性,设计关联必须是单向的。这使你到达了一个阶段,你已经将关联精化成
19、了聚合或是组合。,50,16.7一对一关联,一对一关联几乎都是变成组合。一对一关联暗示了两个类之间的一种非常强的关系,值得注意的是它们是否可以合并成一个单独的类,而不违背任何设计类的设计原则,51,16.8多对一关联,多对一关联发生在整体一端的多重性大于1,而部分一端的多重性恰好是1时。因为整体一端有许多,当部分被许多整体共享的时侯不能用组合,但可以使用聚合。,52,16.9一对多关联,在一对多关联中,在关系的部分一端有一个对象的汇集。为了实现这样一个关系,你必须使用由实现语言提供的固有的汇集支持,或者使用汇集类。大部分的OO语言都提供对对象汇集的最小内建支持(如数组)。数组是对象引用的索引汇
20、集,通常限定为具有一个最大值。内建数组的优点是它们趋于非常快。然而,相对于其他形式汇集的不灵活性而言,速度的优势被抵销。汇集比内建的汇集更加有力和灵活。,53,16.10汇集,汇集类是这样的类,它的实例专门管理其他对象的汇集。大部分的语言都能提供可用的汇集类的标准库(或是其他实用设施)。优秀的OO设计和实现的一个关键是掌握汇集类。所有的汇集类具有下列方法:向汇集中添加对象。从汇集中删除对象。在汇集中检索对象的索引。遍历汇集,即从头到尾步进地检索汇集中的对象。,54,汇集建模策略,汇集建模三个基本的策略:显式地建模汇集类,优点非常明显,缺点是给设计模型添加了许多混乱。汇集类的选择经常是战术的实现
21、决定,可留给开发人员去做;战略性的实现决定,用特定的汇集类来替换一对多关联。告诉CASE工具如何实现每个特定的一对多关联。许多 CASE工具允许为每个一对多关联指派一个特定的汇集类(如添加Vector到适当的关系末端)。说明汇集的语义,但是不要说明任何实现类。重要的是使用汇集时不要“过度建模”。实际使用的汇集类型常常是战术性的,可以将它留给程序员在实现的时候去作合理的假设。,55,简单OCL汇集,OCL(Object Constraint Language)是表示对象约束的形式化语言,是UML1.4规格说明的组成部分。它提供了一组通用的汇集类,提供了OO实现语言中可用的汇集类型的有用范例。OC
22、L汇集是Set、Bag和Sequence。在分析的晚期阶段或是设计的初期阶段,当需要定义一些汇集语义但又不想引入实现语言依赖性的时候,可以选择使用OCL汇集。,56,OCL汇集内容,Set像数学集合重复对象是不允许的。集合中的元素没有索引,并且元素的顺序是随机的。Bag比Set的约束要少一点,允许重复,除此以外,它的语义与Set的语义相同。Sequence同样接受重复对象,但是有索引和排序。这意味着存储在Sequence中的对象就像在数组中一样有索引,并且对象总是维护它们在汇集中的相对位置。,57,映射表,映射表是另一种汇集类类型,也称字典,有点像带有两个字段(关键字和数值)的数据库表。映射表
23、被设计成能根据结定的关键字快速地查找到相应的数值。映射表不是OCL的组成部分,因此如果你想使用映射表,那么你就需强制说明一个语言依赖的实现。,58,例子,因为汇集使用散列表索引,给定特定的关键字,找到对应的数值非常迅速。,59,16.11具体化关系,有些类型的关系是纯分析制品,而且它们自身并不由任何一种普遍使用的OO语言所直接支持。取得这些分析关系并且实现它们的过程通常被称做具体化。需要具体化以下的分析关系:多对多关联。双向关联。关联类。,60,多对多关联,OO语言无法直接支持多对多关联,因此必须被具体化成正常的类、聚合、组合或者依赖。首先你必须确定多对多关联的哪一端是整体,然后再使用恰当的聚
24、合或是组合。,61,双向关联,普通的OO语言不支持真正的双向关联,因此必须将这些双向关联具体化成两个单向关联或依赖,62,关联类,关联类是纯粹的分析制品,在任何普遍使用的OO编程语言中都不能直接实现。必须要将它们从设计模型中除去。将关联类具体化成正常的类,联合使用聚合、组合或者甚至依赖来捕获关联类的语义这可能涉及对模型添加约束。要确定关联哪一端是整体以及使用相应的组合、聚合和导航性。,63,例子,当具体化关联时,已经失去了关联类的语义,但可通过添加包含适当约束的注解来恢复这些语义。,64,小结,本讲介绍将分析关系转化成可实现的设计关系聚合有时能够独立于部分而存在,有时不能。组合是一种强形式的聚
25、合:精化分析关联。关联的不同类型包括一对一关联,多对一关联汇集类是专门的类,它们的实例可以管理其他对象的汇集。有些关系是纳分析制品,并且通过具体化过程变得可实现。包括多对多关联,双向关联,关联类。,65,66,第十七讲 接口和子系统,面向对象的设计与技术,67,17.1什么是接口,接口说明了操作的命名集合。接口的关键思想是通过诸如类或子系统这样的类元将功能性规格说明(接口)同它的实现相分离。接口定义了由类元所实现的契约。例子:IActivate,68,17.2接口规则,接口中的每个操作必须包括:完整的操作签名(名称、参数类型和返回类型)。操作语义可以记录成文本或伪代码。可选的构造型、可选的约束
26、和标记值的集合。接口不能包含:属性。操作实现。从接口到其他任何事物的可导航关系。如实现语言不直接支持接口,就可使用抽象类。,例子,实现关系显示了规格说明和所实现物件之间的关系。在“类”风格记号表示中。实现关系被绘成一条带有空心箭头的虚线;在“棒棒糖”风格记号表示中,它变成了一根没有箭头的实线。,70,17.3接口和基于组件的开发,接口是基于组件的开发的关键,因为接口只是确定契约,允许有任意数目的符合契约的具体实现。例子从图中可以看到接口如何将物件联系到一起而对特定类又不引入耦合。,例子,本例中,GUI子系统只知道CustomerManager接口和AccountManager接口。原则上,你可
27、以用另外一个子系统或者甚至几个子系统完全地替代BusinessLogic子系统。这样使用接口可以提供更好的构架灵活性,例子,这个系统模型中,每个楼层都是一个独立的Zone,每个zone由实现Activate接口的对象集合所组成。这使得非常容易地插入诸如烟雾报警器和ID卡阅读器这样的新设备。,73,17.4寻找接口的方法,查看每个关联并提问,“这个关联确实应该是对象的特定类吗?是否应该比此更加灵活?”。查看每个发送的消息并且提问,“这个发送的消息确实只是到一个类的对象吗?是否应该比此更加灵活?”。分解出可能在其他地方复用的操作组。分解出在多于一个类中重复的操作集合。寻找系统中扮演相同角色的类。寻
28、找未来扩展的可能性,问题是,“在将来可能有其他的类添加到系统中吗?”,74,17.5接口设计,通过使用接口可以设计公共的操作集合,这些操作可能是由许多类实现的。类可以有自反关联,并且自反关联可以成为类内部的角色,这些也是接口好的候选。接口非常强大的作用是提供了将事物插入系统的能力。使系统灵活变化的方法之一是设计能够容易地插入扩展的系统。,75,17.6什么是子系统,子系统是构造型为subsystem的包。子系统用于:分离设计。代表粗粒度的组件。打包遗留系统。设计子系统就是开始组件化模型设计子系统包括:设计类和接口。用例实现。其他子系统。诸如用例的规格说明元素。,例子,子系统图标可分成如下分栏:
29、操作。实现元素。规格说明元素。,77,子系统和接口,当子系统中的类对整体系统中的其他类完全隐藏时,将子系统充当“黑匣子”是有用的。可以通过引入接口并在子系统中将这些接口定义成公共的方法来实现这个目的。子系统中其他大部分的类可以定义成私有的。通过这种方法使用接口,可以将子系统看做一种组件,因为它通过实现一个或多个接口提供了一组服务。,例子,子系统中的公共类实现了接口就称之为子系统实现了该接口。,79,外观模式,将复杂的子系统隐藏在形式良好的、简单的接口后面就是外观模式(Facade Pattern)。“将系统结构化成子系统有助于消减复杂性,共同的设计目标是最小化子系统之间的通信和依赖关系。能够达
30、到这个目标的一个途径就是引入外观对象,它可以为子系统提供更通用的设施”Gamma,80,外观模式接口,外规模式允许信息隐藏和工作分离,可以将子系统复杂详细的内部工作信息隐藏在简单的接口背后。这样就减少了系统的复杂性,并且允许控制和管理子系统之间的耦合。外观的接口具体做法如下:确定系统的内聚部分。将这些打包到一个subsystem。为该子系统设计接口。,81,物理构架和分层模型,设计的子系统和接口的集合组成了模型的物理构架。为了这个构架易于理解和维护,需要将子系统和接口以某种耦合的方式组织起来。可以通过应用分层的构架模式达到这个目的。,82,分层原则,分层模式把设计子系统和接口组织到屋中,每层中
31、的子系统都有语义上的耦合。创建健壮分层构架的本质是通过下列方法管理子系统之间的耦合:在需要的地方引入新的接口。将类重新打包成新的子系统,从而减少子系统间耦合。分层间依赖要尽量解出耦和以保证:依赖是单向的。所有的依赖都是以接口为中介的。,基本分层模式,基本的分层模式是分成表示展、业务逻辑层和实用层。,84,17.7接口的优点缺点,接口的优点:接口针对契约的设计使模型从实现依赖中解放出来,并增加了模型的灵活性和可扩展性。使用接口设计允许减少类、子系统和组件之间的依赖数量,可以控制模型中耦合的数量,将模型分解成内聚的子系统。接口的缺点:追求灵活性和复杂性之间的平衡使系统更加复杂。通常灵活性的代价是性
32、能的降低。,85,OO设计原则,系统建模的正确性要比建模的灵活性重要得多。首先是全神贯注于将系统的关键业务语义正确地建模,然后再考虑灵活性。识别系统的不稳定部分和稳定部分并且相应地为每个部分建模。KISS(Keep Interface Sweet and Simple)原则,保持接口的亲切和简单。,86,小结,本讲介绍接口,接口说明了一组操作,允许软件根据契约设计而不是根据特定实现设计。接口将功能说明从实现中分离出来。接口中每个操作包括完整的签名,描述操作语义的规格说明,构造型、约束和标记值是可选的。接口永远不能具有的是属性,操作实现(方法),从接口到其他任何东西的可导航关系。基于组件的开发(
33、CBD)是关于从插件程序如何构造软件的方法寻找接口和子系统的方法,87,88,第十八讲 用例实现设计,面向对象的设计与技术,89,18.1用例实现设计,用例实现设计是实现用例的设计对象和设计类的协作。在用例实现分析和用例实现设计之间存在trace关系用例实现设计说明了实现决定并且实现了非功能性需求。,90,18.2焦点和组成,在分析中用例实现的焦点是捕获系统应该做什么,在设计中关心的是系统将如何去实现。因而现在必须说明在分析阶段被简单地忽略的实现细节,所以用例实现设计要比原始的分析用例实现更加详细和复杂。用例实现设计由以下各项组成:设计交互图。包含参与设计类的类图。,91,设计要点,应当限制在
34、设计中所做的有用的工作量,仅用建模来帮助理解所要建造的系统就是所谓的战略性设计。设计中的战术性设计是将它们留给实现阶段。事实上,唯一需要彻底设计的时期是你打算从模型中生成大部分代码的时候。因此此时仅仅创建那些需要突出系统行为模糊的方面。,92,18.3交互图设计,交互图是用例实现设计的关键部分,因为它能够更加容易地显示出顺序图中的大量信息,通常在设计时关注这些事物要胜于关注协作图。在设计中引入了有限数目的中心机制,诸如对象持久性、对象分布和事务处理等。设计中的交互图可以是:添加了实现细节的关键分析交互图的精化。创建的全新图以演示设计中产生的技术问题。,例子,我们选择了一个非常简单的持久性机制-
35、:RegistrationManager对象使用:DBManager对象将Course对象保存在数据库中。,94,18.4子系统交互,子系统之间的交互提供了非常有用的高级视图,这是关于构架如何实现用例的而不用进入单个对象交互的低级细节。可以将每个子系统当作通过操作、公布的接口或者接口简单地提供服务的黑匣子。不必担心子系统内部对象间的交互。例如Customer子系统,接口为CustomerManager,例子,例子是顺序图的一部分,显示了参与者和子系统的交互。在交互图上显示传递给该子系统的消息。可以用接口名称来限定消息名称。,96,小结,本讲介绍用例实现设计,事实上只是分析用例实现的延伸。这一阶
36、段实现用例的设计对象和设计类的协作,包括设计交互图,设计类图子系统交互图在一个高层次上显示了系统不同部分之间的交互,可以包含参与者、子系统和类。通常使用描述符形式的子系统交互图。,97,98,第十九讲 基本状态图,面向对象的设计与技术,99,19.1反应型对象及状态图,状态图是对反应型对象动态行为建模的一种非常重要的方法。先前的活动图就是状态图的一种特殊情况反应型对象(从广义上讲)是指一个为状态图提供语境的对象。反应型对象:响应外部事件(即来自于对象语境外的事件)。具有清晰的生命期,被建模为状态、迁移和事件的演化。当前的行为依赖于过去的行为。,100,19.2基本状态图,状态图趋向于对单个反应
37、型对象的生命期历史建模,活动图趋向于对有几个对象参与的业务过程建模。状态图恰包含对应于单一反应型对象的一个状态机。状态图的基本组成元素包括:状态迁移事件,101,动态行为建模,现实世界有许多可用状态机建模的反应型对象。在OO建模中用状态机对如下反应型对象的动态行为建模:类。用例。子系统。整个系统。但状态机在绝大多数情况下用于对类的动态行为建模,102,19.3状态机与类,对每个类而言,一般只需要一个状态机就可以对该类中所有对象对事件响应而引起的状态迁移建模。在典型情况下,事件是由其他对象作为消息传递的。假设一个类中的对象参与了很多用例,你用该类的状态机就可以为类中的对象在所有用例中的行为建模。
38、,例子,电灯泡的状态机每个状态机都有一个初始状态(实心圆),表示状态机开始的位置,还有一个终止状态(牛眼形状),表示状态机终止的位置。,104,19.4基本状态图,基本状态图的语法是简单和直接的,除了状态中的初始状态(实心圆)和终止状态(牛眼形状),其他状态用一个圆角的轻形表示。迁移表示状态问可能的路径,用箭头建模。事件写在由它们触发引起的迁移上。基本语义也是非常简单的:当一个在状态A的反应型对象接收到一个事件anEvent时,它也许会迁移到状态B。,105,19.5状态,“对象生命期中的条件或状况,在此期间,对象满足某些条件,执行某种活动或者等待某些事件”。RumbaughUML参考手册对象
39、的状态是随着时间推移而变化的,但在任何特定时刻,状态由如下因素所确定:对象的属性值。与其他对象的关系。正在执行的活动。随着时间推移,对象相互之间传递消息,这些消息是事件,它们可能引起对象状态变化。,106,说明,每个状态可能包含零个或多个动作和活动。动作被认为是瞬时的,并且不能被中断的。活动需要占用一定的时间,并有可能被收到的事件中断。状态中的每个动作都由事件触发引起的内部迁移相关联。两种特殊的动作入口动作和出口动作,这与入口事件和出口事件联系在一起。,107,状态语法,108,19.6迁移,迁移的语法可以表示外部迁移(箭头表示),也可以表示内部迁移(嵌在在状态内部)。每个迁移有三个可供选择的
40、元素:事件触发迁移的内部或者外部发生的事情。监护条件一个布尔表达式,在迁移发生前必须为true。动作这是和迁移相联系的部分工作,当迁移开始时发生。UML迁移语法的归纳如图所示:,109,19.7事件,“具有时间和空间位置的有意义的事情的规格说明”。RambaughUML参考手册在状态机中,事件触发迁移。事件或显示在迁移之上,或显示在状态内。共有四种类型的事件:调用事件。信号事件。改变事件。时间事件。,110,调用事件,接收调用事件是请求发生一组动作。调用事件应该和为状态机提供语境的类的方法具有相同的签名。可以为调用事件指定一连串动作,每个动作之间用分号隔开。这些动作能够使用语境类的属性和操作。
41、调用事件可能存在返回值,但这个返回值必须符合操作的返回类型。,111,例子,112,信号事件,信号是在对象间异步传递的信息包。把信号建模为构造型化的类,在它的属性中包含了所有的通信信息。可以把反应型对象对信号的接收建模为信号事件。信号事件的事件触发器是将信号作为参数接收的方法,113,例子,114,改变事件,改变事件具有关键字when,后跟布尔表达式。当布尔表达式为真时,执行与该事件相关的动作。布尔表达式中的所有值必须是语境类中的属性。从实现的角度来看,当处在状态中时,改变事件意味着要不断测试条件。改变事件是边缘触发的。,115,例子,116,时间事件,时间事件用关键字when和after表示
42、。关键词when说明被触发的特定时刻,after说明事件被触发之后的阈值时间。在每个时间事件中,要非常仔细地指定时间单位(小时、日、月等)。表达式中的任何符号必须符合反应型对象的属性。,117,例子,118,小结,本讲介绍如何使用类、动作、活动、事件以及迁移来构造基本状态图。活动图是状态图的特例。反应型对象为活动图提供了语境。动作是瞬时的、不可中断的工作。活动需要花费有限时间并且可以中断的工作。它们可能只在状态内部发生。状态是对象在语义上显著的状况。状态语法包括入口动作,出口动作和内部迁移事件是通知反应型对象的事物,类型有调用事件,信号事件,改变事件和时间事件,119,120,第二十讲 高级状
43、态图,面向对象的设计与技术,121,20.1什么是复合状态,复合状态是指包含一个或多个嵌套状态机的状态也称为子状态机。在状态图标中添加分解指示符表示状态图中的复合状态,如图所示。,122,20.2复合状态,复合状态由状态或者子状态组成,对这些状态而言,复合状态是超状态。每个子状态继承了所属超状态的全部迁移。每个子状态本身可能就是复合状态。对嵌套个数有所限制才行除了特殊情况外,嵌套级数应不超过二或三级。复合状态包括两类:顺序复合状态和并发复合状态,20.3顺序复合状态,仅含一个嵌套状态机的复合状态称为顺序复合状态,124,20.4并发复合状态,并发复合状态含有两个或多个并发执行的子状态机。当进入
44、超状态时,两个子状态机开始并发执行这是分叉。有两种离开超状态的方法:两个子状态机同时完成这是结合。其中一个子状态机接收到事件或者结束,并清晰地迁移到超状态外面的状态。这时不会引起结合没有子状态机同步,同时余下的子状态机会终止,例子,一个由控制盒、安全和火警传感器以及报警盒组成的简单防盗警报系统建模。,分叉,InitializingSystem和Monitoring并发执行,127,20.5子状态机通信,在很多情况下,子状态机间需要通信,但又不想通过各子状态机间的同步方式,这就是异步通信的方式。在UML中通过一个子状态机在执行时留下“消息”或者“标志”获得异步通信。其他的子状态机准备好时就可取得
45、这些标志。UML中有两种机制可以做到异步通信反应型对象的属性和同步状态。,128,使用属性通信,对于属性机制,你可以假设正在建模的反应型对象有一组属性值,而这些值可以由它的子状态机所操纵。使用属性进行子状态机通信的基本策略在于一个子状态机可以设定属性,而其他的子状态机可以在迁移的监护条件中使用这些属性值。,129,例子,130,使用同步状态通信,同步状态是一种特殊状态,其目的只是记忆单次输入迁移的每次触发。每次输入迁移触发,该入口被存放在队列中。每次迁移到同步状态外,该入口就从队列中删除。可以在同步状态中写一个整数以声明该队列中允许的入口数量。如果想让同步状态含有无限数量的入口,可在同步状态中
46、书写一个星号*。UML同步状态的语法如图所示。,131,例子,132,20.6历史,复合状态需要某种方法记忆离开时所处的子状态,在需要时可返回离开时的位置,UML中使用历史状态指示符处理这种情况。当使用状态机建模时,经常会遇到的情况有:位于复合状态的子状态中。迁移到复合状态之外(同时也在子状态之外)。经历一个或多个外部状态。迁移回复合状态中,但想继续离开时的子状态。有两种类型的历史状态指示符浅度历史和深度历史。,133,浅度历史,通过浅度历史,只能记忆状态指示符同级别的子状态。历史状态指示符可能有很多引入迁移,但是只有一个引出迁移。这个指示符记忆离开超状态时所处的子状态。如果从一个外部状态回到
47、历史状态时,指示符将自动把迁移导向到最后记忆的子状态。如果是第一次进入超状态,将不会有最后记忆的子状态可以在退出超状态前记忆超状态中最后一个活动的子状态。,134,例子,超状态BrowseCatalog的迁移由如下三个事件引起:exit终止状态机并返回先前所处的状态goToBasket迁移到状态DisplayingBasket(显示购物篮中的当前内容)。goToCheckout迁移到复合状态Checkingout(客户显示总的购物单)。,135,深度历史,通过深度历史,不仅可以记忆和历史状态指示符同级别的子状态,而且可以记忆任何深度的子状态。,136,例子,137,20.7子状态机状态,如果许
48、多状态都含有子状态机,状态图很快就会变得复杂。子状态机状态是一种简化状态图的方法,它允许你引用完整定义在不同图上的子状态机。通过记录复合状态的详细信息,包含对被称为子状态机状态的特殊类型的状态的引用,简化复杂的状态图。,138,例子,139,桩状态,桩状态极像一根水平或者垂直的棒条,表示在被引用于状态机中的子状态。,140,小结,本讲介绍UML丰富的状态图语法,可以用简捷的状态图捕获复杂的行为。复合状态可以含有一个或多个嵌套子状态机子状态机继承了其超状态的所有迁移。顺序复合状态正好含有一个嵌套子状态机。并发复合状态含有两个或多个并发执行的嵌套子状态机。子状态机通信包括属性值和同步状态历史允许超状态记忆引出迁移以前的最后子状态,分为浅度历史、深度历史子状态机状态概述子状态机:,141,