《第10章 状态图.doc》由会员分享,可在线阅读,更多相关《第10章 状态图.doc(25页珍藏版)》请在金锄头文库上搜索。
1、第10章 状态图在一个交互中,可能发送给单个对象一个或多个消息,并且,这些消息以特定的顺序被接收。但是,在另外的交互中,同一个对象可能接收完全不同的消息。根据各个交互的详细情况,特定消息发送到对象的顺序也可能根据情况的不同而改变。通过考虑对象能够参与的所有可能的交互,我们可以看到,在一个对象的整个生存期中,它必须能够合理地响应次序变动范围相当大的消息。在第8章,我们已经看到,对象图不是用来详细说明系统所有可能的状态的。首先,的确存在着太多的状态,不能用文档穷举;其次,除了要知道可能的状态是什么,我们还需要知道哪些状态是不可能,或者不合法的。出于完全相同的原因,顺序图和协作图也不是用来描述对象能
2、够参与的所有可能交互的视图。对这两种情况,解决方案是相同的,即使用表示法的更抽象的形式详细说明系统,而不是举例说明。在UML中,对象的行为规格说明是通过为对象定义状态机来给出的。状态机说明了对象对它在生存期期间可能检测到的事件的响应。在UML中,状态机通常是用一种称为状态图的图来文档化的。交互图和状态机给出的是系统动态行为的两个互补的视图。交互图显示了在较短的一段时间在系统中的对象之间传递的消息,通常是在单个用户产生的事务期间,因此这些图必需描述很多对象,即特定事务中所涉及的那些对象。另一方面,状态图自始至终在一个单个对象的整个生存期中跟踪该对象,指定该对象能够接收的所有可能的消息序列,以及它
3、对这些消息的响应。10.1 依赖状态的行为许多对象展现出了依赖状态的行为。不严密地说,这意味着对象在不同时间将对相同的刺激做出不同的响应。例如,考虑一个简单的CD播放机的行为,播放机包括一个装CD的抽屉,如果当前有播放的CD,就放在抽屉里。还包括一个界面,界面包含三个按钮,标明“装入(load)”、“播放(play)”和“停止(stop)”。如果当前抽屉关着,装入按钮使之打开,如果是打开的,则使之关闭。停止按钮使播放机停止正在进行的播放。如果没有正在播放的CD时,按下停止按钮不起作用。最后,播放按钮播放抽屉中的CD,如果按下播放按钮时抽屉是打开的,则先关闭抽屉后再开始播放。这个CD播放机至少在
4、两个方面表现出了依赖状态的行为。例如,如果抽屉开着,按下“装入”按钮将关闭抽屉,而抽屉关着的时候,按下“装入”按钮将打开抽屉。另外,如果正在播放CD,按下停止按钮就停止播放,但是如果没有播放CD,按这个按钮没有作用。在这个例子中,我们可以标识CD播放机能够处于的至少三个不同状态。按下“装入”按钮引起的不同结果表明我们需要区别“打开(open)”和“关闭(closed)”状态,而按下“停止”按钮的不同结果表明存在第三个状态,可能标记为“正在播放(playing)”,它不同于上面任一个状态。同样值得注意的是,CD播放机可以响应事件而改变状态。例如,重复地按下“装入”按钮将引起CD播放机在打开和关闭
5、状态之间转换。这个例子中的三个状态符合CD播放机的实际状态中可观察到的差异确实令人愉快,但是情况并不总是如此。区分状态的基本原则是,处于一个特定状态的对象,对至少一个事件的响应和它处于其他状态时对该事件的响应不同。因而识别的状态可能对应于容易发现的对象的外部特征,也可能并不与之对应。用于行为建模的状态的概念应该区别于第2章所讨论的状态,在第2章,对象的状态被定义为在给定时间其属性的值的整体。状态的行为概念比这个更广泛:在两个时间一个对象的属性很可能不同,可是却处在相同的行为状态。对此,CD播放机的“关闭”状态可以提供一个例子:抽屉中有或者没有CD可以被认为是CD播放机不同的属性值,但是在任一情
6、况下我们都可以认为播放机处于关闭状态。行为状态的识别并不是一个严格的过程。状态的不同,是通过处于不同状态的对象对事件的响应不同来区分的,但是什么看作是不同的响应,在某种程度上却是一个需要判断的问题。行为状态的重要特性是,第一,一个对象有若干个可能的状态,并且在任何给定时间恰好处于这些状态中的一个。第二,对象可以改变状态,通常,它在给定时间所处的状态会由它的历史决定。最后,在不同时间,一个对象可能依赖其状态对同一刺激做出不同的响应。10.2 状态、事件和转换状态图(statechart diagram,通常简称为statechart),显示一个对象可能的状态,它能够检测到的事件,以及它对这些事件
7、的响应。因此,为了构造一个对象的状态图,我们必须首先至少暂时地确立对象能够处于什么状态以及它能够检测什么事件。比如CD播放机的例子,我们已经标识了打开、关闭和正在播放状态,这将作为开发状态图的基础。用软件的术语,经常假定,对象检测到的事件就是发送给它的消息。然而,在刚开始设计时不必要这么具体:需要的只是对象能够检测到的外部事件这个更一般的概念。在CD播放机的例子中,能够检测到的外部事件只是按下三个按钮。因此,CD播放机的状态机将包括至少三个事件:“装入(load)”、“播放(play)”和“停止(stop)”。一般而言,检测到一个事件可能导致对象从一个状态移动到另一状态,这样的移动称为转换。例
8、如,如果CD播放机处于打开状态,按下装入按钮将引起抽屉关闭,并且CD播放机移动到关闭状态。状态图上显示的基本信息是实体的可能状态以及它们之间的转换,或换句话说,检测各种事件的路径引起系统从一个状态转换到另一个状态。描述CD播放机的基本模型的状态图如图10.1所示。系统的状态以圆角矩形表示,其中写着状态的名字。状态转换用连接两个状态的箭头表示。每个这样的箭头必须标注一个事件的名字。这种箭头的含意是如果系统在处于箭头尾的时候接收到该事件,它将转到箭头的头所指向的状态。因此,事件通常将在状态图中出现多次,该对象可能在多个不同的状态检测到同样的事件。 图 10.1 CD播放机的一个简单状态机在图10.
9、1中,从每个状态都有三个出发的箭头,每一个事件都可以被CD播放机检测到。这种完备性不是状态机的基本性质,而只是反映了CD播放机的用户在任何时候都可以按下三个按钮中的任何一个的事实。如果事件没有引起状态的改变,那么相应的转换只是在一个状态上形成回路。这种情况的例子是,在CD播放机已经处于正在播放状态,检测到播放事件时发生的转换。这样的转换被称为自转换(self-transition)。事件如同消息一样,能够带有数据,写在消息名字后面的括号中。播放机的例子中没有需要携带附加数据的事件,但在10.10节考虑的例子中将看到这样的例子。状态机的执行一个简单的状态机,如图10.1中所示的状态图,可以认为是
10、按照下面的方式“执行”。在任何给定时刻,对象恰好处于图中所示的状态之一。这个状态称为激活状态(active state)。任何从激活状态出发的转换都是一个候选激发。例如,如果CD播放机的激活状态是“打开”状态,那么候选激发的转换有该状态上的自转换、标记着“装入”的到关闭状态的转换,以及标记着“播放”的到达正在播放状态的转换。能够引起转换激发的事件称为触发器(trigger)。当检测到一个事件时,该事件将激发从激活状态出发的标注着该事件名字的转换。这个激发的转换的另一端的状态就成为激活状态,这个过程可以再次重演,不同的是现在的候选激发将是从新激活状态出发的转换。从当前状态出发的事件如果没有标注为
11、所检测到事件名字的,就忽略该事件,不激发任何转换,当前状态仍是激活状态。如果有必要指定在一个状态是激活的情况下检测到一个特定事件是错误的时候,可以定义一个错误状态,并增加一个到错误状态的转换并用被禁止的事件的名字加以标注。10.3 初始状态和终止状态图10.1中的图描述了CD播放机在使用时的运作机能,但是没有说明机器在开关时发生什么。我们将假定关机器时它不表现出任何行为,当开机时它总是直接到关闭状态。我们可以通过向状态图中加入初始状态表示后一种行为;初始状态用黑色的小圆点表示。从初始状态出发的转换表示创建或初始化对象时进入的状态。CD播放机的初始状态如图10.2所示,初始状态上的转换表示播放机
12、在开机后总是处于关闭状态。注意从初始状态出发的转换上不应该写任何事件。 图 10.2 初始状态和终止状态除了初始状态,状态图还可以表示终止状态。终止状态代表对象在响应撤销、关掉,或其他终止事件时到达的状态,终止状态用大圆圈中加一个小圆点表示。一般而言,可以从许多不同的状态到达终止状态。在CD播放机的例子中,引起达到终止状态的事件是关播放机。我们可以用一个称为“关机(off)”的新事件对此建模。可以在任何时刻关掉播放机,因此用标注为“关机”事件的转换将终止状态连接到所有其他状态。终止状态的含意依赖于状态图所描述的对象的特性。如果一个软件对象,即类的实例,到达它的终止状态,那么它将完全被销毁:如果
13、它有析构函数,那么将调用析构函数,并回收对象占用的内存。然而,图10.2显然不应该被解释说CD播放机在每次关机时都被实际地销毁:这样的设计不可能制造出来投入市场。实际模拟的是控制CD播放机的软件的行为:当关掉播放机时终止控制程序,并且机器将不响应任何事件,直到再次开机。10.4 监护条件图10.2中的状态图对CD播放机的行为给出了一个过分简单的描述。有一个问题是,当按下播放按钮时,播放机并不总是进入正在播放状态,而是当检测到该事件时如果抽屉中有CD才进入正在播放状态,否则如果抽屉还没有关闭就只是关闭抽屉并且进入关闭状态。这意味着在准确的模型中,关闭和打开两个状态都应该包含始于它们的两个标注为“
14、播放”的转换。在任何给定时刻,实际上沿哪个转换前进将取决于在该时间抽屉中的内容。 图 10.3 按下“播放”时的两种可能后果图10.3显示了在CD播放机抽屉关着的时候按下“播放”按钮的两种可能的后果。这是一个非确定状态图的例子。这个图表明播放事件可以触发两个可能的转换,但并没有说明何时将激发其中的一个转换而不是另一个。原则上,不确定的图没有任何错误,但是如果建模的系统事实上是确定的,那么不确定的图必定是遗漏了系统的某些信息。在CD播放机的例子中,当按钮按下时不存在真正的非确定性,因为播放机接下来的行为由抽屉中的内容确定。更准确的模型应该表明是什么导致沿着一个转换而不是另一个转换前进,以消除图1
15、0.3中呈现的非确定性。在状态图上,这样的信息可以通过为播放转换增加监护条件来表示,表明在什么情况下将激发该转换。监护条件是转换的规格说明的一部分,写在标注该转换的事件名字之后,并用方括号括起来。监护条件通常以非正式的英语写出,如这里一样,但是如果要求,可以用更形式化的符号,如第12章描述的OCL语言写出。图10.4所示的CD播放机的扩充状态图包括了监护条件,区分了抽屉的非空和空的状态。为了简单起见,与当前讨论无关的初始状态和终止状态在这个图中省略了。 图10.4 使用监护条件区分转换监护条件对状态机执行的影响如下。当检测到一个事件时,将对标注着该事件名字的转换上的监护条件求值。如果转换有监护
16、条件,那么只有在求值为真时这个转换才会激发。如果所有监护条件都是假值,并且没有无监护的转换,就忽略该事件。如果多个转换有值为真的监护条件,那么它们中只能有一个被激发。在这种情况下,非确定性再次引入到状态机,通常,要对一组离开转换上的监护条件进行挑选,以使得在任何给定时间,为真的不能超过一个。例如,假定CD播放机正处于打开状态时按下了播放按钮。发生的第一件事情是关闭抽屉;这是必要的,以便机器能够检测是否有碟片。重要的是要注意在这个时候,尽管事实上抽屉是关闭的,但CD播放机并不是在关闭状态。仍然是在打开状态下,评估播放转换上的监护条件的值,看应该激发哪个转换。这阐明了前面提出的一点,CD播放机的状态机中的状态不必要和CD播放机的实际状态恰好对应。如果有CD,将激发从打开状态到正在播放状态的转换。状态机直接从打开转到正在播放状态,并且不经过