序列图交互建模中的常见错误及其纠正方法。
常见错误 | 纠正错误 | 举例 |
不将序列图中的对象映射到类图中的类 | 确保序列图中的每个对象在类图中都有相应的类 - 设计完成时。 | 序列图中的患者应该属于类图中的患者。 |
不将序列图中的消息映射到类中的方法 | 确保序列图中的方法在类图中具有相应的消息(操作功能)。 | 序列图中的+ enquiresavailability()消息应对应于类图中类(本例中为Doctor)中的相同方法。 |
将消息箭头指向发送对象(而不是接收对象) | 消息箭头指向必须执行操作的对象 - 而不是发出请求的对象。 | 如果Patient对象正在检查aDoctor的可用性,则消息+ inquire availability()上的箭头将指向Doctor而不是aPatient。 |
使用消息箭头指示返回消息 | 前进消息箭头很粗,返回箭头是虚线。 | 图12.5显示了带有虚线箭头的返回协议(或本例中消息可用性的返回值); 此可用性不是新消息,而是返回给调用对象的值; 此返回值不应使用粗(正常)箭头显示,而应使用虚线箭头显示。 |
试图显示if-then-else场景 | 序列图是及时的快照。 他们无法表现出条件。 | 本章中的所有序列图都没有if-then-else图12.1显示序列图的主要符号也没有规定在该图中显示的条件。 |
不理解控制的焦点 | 确保仅在消息继续保持焦点(在控制中)一段时间以及一系列后续消息时才使用控制焦点。 | 图12.5显示了控制的重点。 这种控制焦点从getSchedule()消息开始,并且仍然超出可用性的返回值。 此模型表示组中的消息全部在一起并保持对系统的控制,直到该组被执行。 |
不理解内存中的对象破坏 | 需要从内存中正确删除对象; 否则,他们会在每次执行系统时都会产生“垃圾”。 | 图12.6显示了在该组消息执行结束时从主内存中删除(删除,销毁)aPatient。 这在aPatient的时间轴末尾用“X”表示。 请注意:在从内存中删除aPatient后删除PatientForm。 |
学习目标
◾了解与序列图的交互建模
◾在问题空间中创建基本序列图
◾在解决方案空间中创建高级序列图
◾在序列图中显示对象的创建和销毁
◾了解序列图中控制的重点
◾使用序列图增强和丰富类图
◾研究序列图的优点和局限性交互建模本章将序列图作为模型交互的关键机制,它是对象之间消息的实时交换。对这些交互进行建模是理解系统动态的重要部分。这是因为UML的交互模型基于“时间”。与静态结构模型(例如类图)相比,交互图形成动态建模的基础。
UML中的两个交互模型是序列图和通信图(也称为早期版本的UML中的协作图)。序列图模拟系统中协作对象之间的消息序列。通信图与序列图的用途相同,但视觉上不同(参见第2章中的图2.7)。
关于序列图分析中的序列图(问题空间)根据actor(用户)的观点对系统的行为进行建模。因此,序列图是一种很好的“白板”技术,用于捕获用户描述的各种使用场景。设计级序列图更加详细,显示了在给定序列中彼此协作的对象。设计级序列图还包含详细消息,这些消息的序列,消息中的参数列表以及消息的返回值。这些图有助于建模者可视化对象和在对象之间传递的消息。它们代表系统中的场景或示例。
使用序列图建模从对象开始。由于对象基于类,因此序列图与类图具有紧密的联系。因此,创建动态序列图可以增强和升级结构类图。理解这种交叉图建模和增强对于在软件工程中成功使用UML非常重要。类序列图依赖性表明UML不是许多图的各种集合;相反,基于元模型的许多图之间存在紧密的依赖关系。
序列图显示了对象和actor的行为。因此,时间概念以及对象之间的依赖关系出现在序列图中。反过来,这使序列图能够显示系统中“发生了什么”。
然而,使用序列图的整个动态建模在给定的时间范围内。
因此,序列图显示事件的“快照”。它们不能用于模拟端到端消息传递(这是用例和活动图的范围)。
序列图中的详细符号的序列图图12.1显示了序列图的关键符号。这些表示法包括以下内容:actor,对象,时间轴,控制焦点,消息,自我消息,返回消息,异步消息,对象销毁,步骤(按顺序)和注释。其中许多符号是可选的,因为它们的使用取决于建模空间。例如,“焦点控制”和“返回消息”可能不会用在问题空间(MOPS)模型中。然而,这些符号在解空间(MOSS)模型中具有重要意义,因此在那里被广泛使用。另一方面,actor(图12.1中的Patient)表示用户扮演的角色(用例的一部分)。这个actor有助于从MOPS中的用例建模场景,但在MOSS中没有多大价值。
在图12.1中是属于Patient类的aPatient对象的示例。有时,对象在序列图中单独显示 - 未显示为属于相应的类。但是,设计中的每个对象都需要与相应的类链接。在其他时候,类名出现在没有对象的序列图中,例如:患者。在这种情况下,:假定患者是属于患者类的匿名对象。无论序列图中的表达式是什么,它仍然只显示实例级对象而不是类。
图12.1中的下一个符号是从对象下来的虚线,表示该对象的时间轴。时间轴表示该对象的时间消息序列。
偶尔,从物体下来的时间线会变粗。时间线的这种加厚表示特定对象在消息交互期间具有“控制焦点”。在设计中特别需要控制焦点以指示哪个特定物体在给定序列中负责或活动。控制的焦点还表示从对象发送的消息处于活动状态并等待响应完成的时间(本章稍后将对此进行说明)。
消息表示对象之间的通信。序列图上的消息符号显示在图12.1的右侧。序列图中的消息从一个对象时间轴转到另一个对象时间轴。此消息流导致对接收对象上的方法的调用。消息通常从左到右显示。有时,消息也可以从右向左 - 取决于在类中激活的方法。请注意,接收要处理的消息的对象具有消息的箭头。
虽然消息通常从一个对象时间轴发送到另一个对象时间轴,但它们也可以由对象发送给自己。在这种情况下,使用自我消息表示法,如图12.1中的下一个所示。
图12.1接下来显示了一个返回消息,用虚线箭头表示,表示提供了对消息的响应。此响应补充了原始消息。配对消息及其返回消息通常在解决方案空间中建模。
异步消息表明发送对象在继续执行序列中的下一条消息之前不必等待接收对象的响应。半箭头显示异步消息(图12.1)。
正常消息箭头用于显示对象的创建。但有时需要显示对象的破坏(删除)。这由被删除对象的时间轴末尾的“X”(图12.1)显示。此表示法表示该对象已从内存中删除。
可以在序列图的左侧(侧栏)(图12.1中标记为“步骤”)提供与消息相关的文档,并在序列图中自由使用这些注释以提供解释。
序列图往往是技术性的,在设计上更加详细。例如,设计中序列图中消息的格式如下:sequence-number sequence-iteration:message(arguments):return-value对应于前一格式的序列图中的消息如下:1 :getSchedule(DoctorID,Schedule):void或者,可以通过消息返回一个计划,如下所示:1:getSchedule(DoctorID):Schedule图12.2显示了序列图的基础知识。这些是:
◾协作对象 - 这些对象发送和接收消息,从而实现特定的系统行为。这里显示的两个合作对象是患者:患者和医生:医生。
◾消息显示为由aPatient发送到aDoctor对象 - 消息是getSchedule(DoctorID,Schedule):Void。此消息由aPatient发送,还具有包含DoctorID的参数列表,并且aPatient对象从aDoctor接收。
◾时间线表示对象之间交互的时间进度,因此表示协作对象发送和接收消息的顺序。
将序列图与类图相关联
序列图不是孤立绘制的。序列图更新并丰富了设计过程中先前绘制的类图。类和序列图之间存在相互依赖关系。每个图表都为其他图表增加了价值。因此,必须理解两个图之间的这种紧密映射。
序列图到类图的这种映射的基本原理如图12.3所示。在图12.3a中,序列图的一部分显示为对象aPatient:Patient。对应于此对象的类显示在图的右侧:class Patient。因此,对于序列图在语义上有意义,必须将该序列图中的对象映射到类图中的相应类。大多数UML建模工具通过在序列图中显示与对象相对应的类列表并为设计者提供选择的类来促进此映射。如果不存在与序列图中创建的对象相对应的类,则建模工具便于创建该类。
因此,序列图也成为识别缺失类的机制。可以存在与类图对应的多个序列图。这是因为序列图仅显示一个特定序列(快照),而类图显示处理所有可能序列的类。
图12.3b还显示了aPatient对象收到的消息,如下所示:checkPatientDetails(P_ID = 101,P_Details):Void对应于前一条消息的方法也显示在图12.3b右侧的类中。此映射表明序列图中显示的消息需要类图中的相应方法。此外,由于接收消息的对象(aPat)应该能够理解消息,因此需要在对应于该对象的类中具有相应的方法[即,Patient类必须具有设计和编码的checkPatientDetails()方法。在里面]。
因此,消息(出现在序列图中)可以被认为是方法的实例(出现在类图中)。尽管这里讨论的两个图之间的映射非常接近,但序列图与类图或用例没有一对一的关系。一个序列图可能会跨越许多类图。许多序列图可以更新类图。
推进从分析到设计的序列图在分析过程中,序列图可用于表示用例中记录的交互。因此,分析中的初始序列图可以仅用两个对象绘制:actor和系统,如图12.4a所示。分析期间允许任何其他对象在序列图中,但不是必需的。这样的序列图表示用于记录用例的“参与者 - 系统”交互格式。
图12.4b显示了设计级序列图如何不能将系统作为接收消息的对象。相反,有必要指定“系统的哪个部分”负责接收然后发送消息 - 由图12.4中的医生:医生显示。请注意,它不一定只是接收消息的单个aDoctor对象 - 作为详细序列的一部分,可以存在接收消息,处理和发送它们的对象的协作。
理解控制和返回消息的焦点图12.5显示了解决方案空间中特定的序列图的一个重要方面。
这里,Patient对象显示向Doctor对象发送message-getSchedule()。
但是,在该消息之后,Patient对象下面的时间线会变粗。这意味着aPatient对象现在可以“控制”交互。
aPatient对象发送的第二条消息是getAvailable()。尽管第二条消息是由aPatient发送的,但控件仍然保留在aPatient中。这意味着系统将等待aPatient完成其消息序列并放弃其控制,然后才能发送或接收来自其他对象的消息。
第二条消息getAvailable()也与其响应可用性配对,由虚线返回箭头显示。这是返回消息箭头。显示此返回并不是强制性的,因为在大多数情况下,消息本身意味着返回值。
此外,当在时间线上存在控制焦点时,暗示焦点保持直到调用对象已经接收到有意义的返回值。
例如,在图12.5中的序列图的情况下,getSchedule()消息在系统中有许多其他消息,这些消息有助于为getSchedule()生成所需的结果。此类消息的一个示例是getAvailable()消息。在所有这些消息的末尾,getSchedule()接收一个有意义的答案 - 在其参数列表中或在其签名中的返回值中。只有在完成整个消息序列之后,才释放对aPatient对象的控制焦点,并且时间线恢复正常。创建和销毁对象图12.6演示了设计中序列图中两个其他重要函数的建模 - 对象的创建和销毁。在图12.6中,对象的创建由直接指向对象的消息箭头显示(与对象的时间轴相对)。指向对象的消息箭头表示对象的时间轴已经开始 - 换句话说,该对象已经在该时间点(系统创建了对象)中出现在系统中。在以下情况下显示了对象创建的另一个示例(C中的构造函数):PatientForm创建aPatient。在构造函数的第二个示例中,还显示了创建aPatient的对象;它是边界对象:PatientForm。
图12.6中演示的另一个重要符号是析构函数。这是aPatient对象和:PatientForm对象在时间轴末尾显示的“X”。
析构函数指示从内存中删除对象。在系统执行期间删除对象很重要,因为否则系统中没有用途的对象可能会继续耗尽内存并可能损坏系统。
医院管理系统中的序列图问题空间中的序列图本节显示了四个序列图。这些序列图模拟了需求的快照。因此,这些序列图在问题空间中增加了价值。
对应于“RegistersPatient”用例的序列图如图12.7所示。在此序列图中,:ActorPatient宣布他到达管理员。此消息(交互)位于两个actor-ActorPatient和Administrator之间。由于消息未发送到系统内的对象,因此此交互发生在系统外部。患者提供详细信息(身份和保险)。这些详细信息由管理员使用界面提供给系统。类System仅存在于此问题空间分析级序列图中。在解决方案设计中,没有系统类,因此没有相应的对象。但是,在设计中,属于特定类的许多对象将取代系统。
此System对象(假设)向系统(自身)发送消息以验证和验证患者详细信息。 GHRS(政府健康管理系统)课程还通过界面对医疗保险细节进行了额外的验证。
在验证和验证患者详细信息时,系统会将另一个自我消息发送到CreatePatientRecordID()。随后,系统生成PatientRecordID,其为与患者的所有通信提供基础。
图12.8显示了通过发送消息ShowCalendar(),通过接口对象更新Staff actor发起的Calendar日程序列。反过来,aInterface对象将消息发送到Calendar对象并检索日历的详细信息。然后,演员工作人员使用aInterface对象输入他首选的名单详细信息。
验证检查将发送到Calendar对象。此过程启动两个自我消息:ValidateRosterDetails()和UpdateCalendar()。完成所有验证后,演员工作人员接受名册详细信息。
图12.9显示了Booking a Consultation序列图。 actor通过SpecifyInitialConsultationDetails()消息启动消息序列,该消息被发送到aInterface对象。该消息导致医生对象通过aInterface向演员Patient提供的医生列表。患者从提供的清单中选择医生。然后,Calendar对象提供所选医生的可用日期和时间列表。然后患者选择日期和时间,并向Calendar对象发送消息以更新日历。演员患者确认他的预订图12.10显示了支付账单序列图。演员通过请求显示付款细节来启动事件序列。收到BPay的回复后,演员Patient会验证BPay声明。然后患者继续为收到的付款声明付款。此事件从BPay对象向Bill对象发送消息,以更新相应计费参考号的记录。 Bill对象生成已支付金额的收据。 BPay对象确认与演员Patient的收据。
解决方案空间中的设计级序列图图12.11
显示了解决方案空间中绘制的高级序列图。这个图由设计者绘制,用于模拟各种类型的对象之间的详细交互,由各种刻板印象表示(第10章)。图12.11显示了<< boundary >>和<< table >>类以及<< entity >>类(请注意,这里使用的术语类表示属于该类的对象)。这些构造型中的每一个都在图12.11中以相应的图标显示。
在图12.11中,:PatientForm边界对象向aPatient:Patient发送消息bookConsultation()。为了预订咨询,aPatient对象向名为getSchedule()的:Doctor对象发送消息。虽然getSchedule(DoctorID,Schedule *)上的参数未在图中显示,但它们由aPatient传递给:Doctor。 :Doctor反过来将消息getDoctorRoster()发送到名为:DoctorTable的<< table >>对象。 :Doctor然后还将消息getPatientRecord()发送到:PatientTable。一旦通过:Doctor对象从表对象中检索到这些细节,aPatient对象就会发送另一条消息给:Doctor以获取doctor-getAvailable()的可用性。在此消息的情况下,图中还显示了指示可用性的返回消息。然后:从内存中删除PatientForm。
在设计中注册患者序列图图12.12描述了注册患者的事件序列。在收到注册新病人的请求后,<< control >>对象:TransactionManager通过消息Display()
创建一个<< boundary >>对象:PatientRegistrationInterface。新患者的详细信息将输入此表单并保存,其中将消息发送至:TransactionManager,该患者使用消息updatePatient()从患者类创建患者对象的新实例。 :TransactionManager进一步向<< control >>对象发送消息:DatabaseManager,它从患者对象请求getPatientDetails(),然后通过消息savePatientRecord()将详细信息保存在:PatientTable中。完成此序列后,对象:PatientRegistrationInterface,:Patient和:PatientTable将被销毁。
请注意,对象的“销毁”仅意味着在执行期间将其从内存中删除。
序列图中的“X”并不意味着从系统的存储设施(数据库)中完全擦除对象。在设计中更新日历序列图在图12.13中详细说明了更新日历的顺序。 << control >>对象:DatabaseManager首先通过向它发送消息create()来创建:CalendarTable。
:DatabaseManager将第二条消息checkSchedule()发送到:Calendar << entity >>对象。如果发现时间表是正确的(例如,对于正确的医生),那么具有必要参数的第二消息getScheduleDtls()被发送到:日历。计划通过以下消息保存在:CalendarTable中:DatabaseManager saveSchedule()。
设计中的“更改预订时间”序列图图12.14描述了更改咨询预约时间的事件顺序。新预订时间的详细信息输入:ConsultationBookingForm并提交,其中将消息changeConsultation()发送到咨询<< entity >>对象,aConsulation。 aConsultation从这里发送两条消息到两个预订对象:第一个到10amBooking,告诉它deleteBooking()(销毁自己),第二个到4pmBooking到createBooking()。完成此操作后,a咨询会发送自我消息以更新咨询预约。
设计中的“支付账单”序列图在图12.15中,描述了支付账单的顺序。首先,<< control >>对象:PaymentManager通过消息createPaymentForm()创建<< boundary >>对象:PaymentForm。 :PaymentManager然后通过从以下方面获取相应的详细信息来填充表单:Patient并将displayPaymentForm()发送到表单。当以这种形式提交付款细节时,:PaymentManager将savePayment()消息发送到:TransactionManager,它与外部参与者接口:A96- VisaInterface以验证信用卡交易。由于此序列仅描述成功付款,因此下一条消息由以下内容发送:TransactionManager将付款详细信息保存在:PaymentTable << table >>对象中。
通信图通信图还显示了对象,它们之间的交互以及相互之间的链接。
通信图中的信息类似于序列图中显示的信息。因此,他们只是在这里简要提到。应在创建序列图后进行通信图的实验。
在一些建模工具中,可以通过按下按钮将序列图转换为通信图。这证明了这两个UML图的接近程度。因此,本书不再讨论通信图。
序列图的优点和缺点
以下是序列图在建模中的优势:
1.序列图可以用图形方式显示用户描述的“示例”。它们提供了从这些示例构建故事板或场景的机制。因此,它们也可以成为移动应用程序开发的良好起点。
2.序列图显示在给定时间段内在协作对象之间传递的消息序列。排序信息在设计中最有用,因为它显示了前提条件。
它们提供了系统中一段时间内发生的事情的理想“快照”。
4.序列图可以识别丢失的对象,可以将其作为类添加到类图中。
5.序列图可以识别类中缺少的操作,可以在类图中添加。
6.作为“实例图”,序列图能够在图中显示属于同一类的多个对象。例如,序列图可以包含属于Patient类的两个或更多个患者对象(aPatient和bPatient)。 (注意不可能在类图上显示属于同一类的这两个患者对象。)7。序列图可以显示在两个或多个对象之间多次传递的相同消息。例如,如果aPatient对象向aDoctor发送一个名为checkAvailability的消息,那么在再发几条消息之后,可以再次向同一个消息发送checkAvailability消息。序列图显示传递给相同对象的多个对象,多个消息和消息的能力显示了图的一些动态强度。
8.序列图和类图之间的映射增强了类图的质量。这是因为单步执行序列图可以揭示(a)缺少的类和(b)类中缺少的方法。
9.带有签名的方法是设计人员和程序员如何设计消息(操作)的详细设计级信息的丰富来源。
10.显示对象销毁有助于确保在执行期间删除对象(从而减少内存混乱)。
以下是序列图在实践中的弱点:
1。序列图是两个时间帧之间的快照,在某种程度上是一个“不完整”的图表。它并不意味着显示完整的流程或流程,如在用例或活动图中记录的,从开始到结束。因此,这些图表不能(也不应该)用于完整的流程文档。
2.在序列图中很难显示“if-then-else”或“for-next”条件。因此,不应使用序列图来描述这种情况。
3.序列图只能表示进程中的单个流或线程。
多个线程需要多个序列图以进行适当的建模。但是,两个序列图之间没有关系。交互概览图克服了序列图的这种弱点,交互概述图可以显示多个线程以及包含许多序列图的“if-then-else”场景。
4.尝试在序列图中完成整个序列可能会导致难以置信且令人困惑的序列图。应该按照序列图仅对详细序列的适当(重要和/或复杂)子集建模。
5.给定设计中所需的序列图的数量尚不清楚。这取决于设计师在何时停止开发它们的经验。从理论上讲,可以在给定的设计中绘制出许多序列图。
6.系统设计人员使用这些图表(技术级别)的方式与业务分析师使用这些图表的方式(业务流程级别)不同。这些图表的不当使用类型在实践中可能会产生相反的效果。