今天,繼續我們的UML之旅。
今天,我們將瀏覽一下UML中的狀態機圖。
狀態機圖(State Machine Diagram)是系統分析中常用的一種工具,它用于描述一個對象在其生命周期內所經歷的各種狀態,以及狀態之間的轉移、引發轉移的事件或狀態轉移的活動。
狀態機圖主要用于對類或對象的動態行為進行建模。也可以對一個用例,或整個系統進行建模。
狀態機由狀態、轉移、事件和動作等組成。
狀態(state)是指對象在其生命周期中,滿足某些條件、執行某些活動或等待某些事件時的一個狀況。
如圖書館的一本書籍可能有:“在架”、“借出”、“被預借”等狀態;讀者可能有“已綁定借閱卡”、“未綁定借閱卡”、“被限制借閱”等狀態。
在UML中,狀態使用圓角矩形表示,一個狀態有自己的狀態名稱,狀態中包含該狀態下將執行的動作和事件。
圖1 借閱圖書狀態
如上圖是借閱系統中借閱圖書的一個狀態。
entry、do和exit是標準的三個動作,分別是進入狀態時的動作,處于該狀態下執行的動作和退出該狀態時的動作。
且可以在該狀態下定義相應的事件動作event。
entry為進入動作,當進入該狀態時要執行的動作;
exit為退出動作,當離開當前狀態時要執行的動作。
除了這種標準狀態之外,UML中還定義了初始狀態、結束狀態、組合狀態、子狀態和歷史狀態。
(1)初始狀態
初始狀態代表狀態機圖的開始,使用實心圓表示。一個狀態機圖只有一個初始狀態。
圖2 初始狀態
(2)結束狀態
結束狀態表示一個狀態機圖的結束,使用實心的圓環表示。一個狀態機圖可以有多個結束狀態。
圖3 結束狀態
(3)組合狀態
組合狀態是狀態內部嵌套有子狀態的狀態。一個組合狀態包含一系列子狀態。
而沒有嵌套的狀態稱之為簡單狀態。
嵌套在一個狀態內部的狀態為子狀態??梢愿鶕顟B是否同時存在,可以再細分為順序子狀態和并發子狀態。
順序子狀態:在組合狀態的生命周期中,任何時刻只能處于一個子狀態,即多個子狀態之間是互斥的關系,不能同時存在。
如下面的圖中演示一部手機處于“給某人打電話”這種組合狀態時,其子狀態不能同時存在,是一種順序的子狀態。
圖4 組合狀態之順序子狀態
并發子狀態:多個順序的子狀態可以同時存在。下圖給出一輛汽車行駛中的組合狀態。低速和高速這兩個狀態是順序的子狀態,在某一時刻只能處于其中一個狀態;前進和倒車也是如此。但這兩個順序的子狀態又可以同時存在。
圖5 組合狀態之并發子狀態
歷史狀態:歷史狀態是一種偽狀態,它表示在狀態再次轉移到該組合狀態時,應處于上一次退出時的一個子狀態。
圖6 組合狀態之歷史狀態
上圖給出了一個音樂播放器的一個狀態機圖。其中“播放”標記為歷史狀態。其含義是在播放狀態轉移到暫停狀態,當由暫停再進入播放狀態時,其應進入“播放”狀態退出時的一個子狀態,它可能在退出時是“順序播放”狀態,也可能是“隨機播放”狀態,也可能是“倒序播放”狀態,但必須是退出“播放”狀態時所處的一個歷史狀態。
轉移(Transition)指的是兩個不同狀態之間的一種關系,是對象在滿足一定條件或發生某個事件時,從一種狀態遷移到另外一種狀態。
圖7 狀態轉移
一個轉移一般包括源狀態、目的狀態、觸發事件、警戒條件和動作5部分組成。
也就是說事件的發生導致了從源狀態到目的狀態的轉移。
(1)源狀態
是受轉移影響的狀態,當事件發生或滿足警戒條件時,就會激活一個轉移。
(2)目的狀態
轉移完成后的狀態。
(3)觸發事件
當源狀態的對象接收到事件時轉移才有可能被激活。觸發事件有自己的名稱,也可以有自己的參數。
(4)警戒條件
轉移激活前需要滿足的一個條件。警戒條件往往是一個邏輯表達式,其值為真或假。觸發事件發生,且警戒條件為真時,轉移才會被激活。否則,本次事件將被丟棄,只能等待下一次觸發事件的發生。
(5)動作
當轉移被激活時,對應的動作也會被執行。動作一般可以是一個賦值操作或算術運算,也可以是調用目的對象的一個操作或創建、銷毀一個對象,也可以是用簡單語言來說明動作的含義。
圖8 動作
上圖中是圖書由“在架”狀態轉移到“被預借”狀態的一個例子。
源狀態是“在架”,目的狀態是“被預借”,“讀者預借”是觸發事件的名稱,“圖書編號”是觸發事件的參數,“讀者預借數量<=1”是轉移的警戒條件,“添加預借記錄”和“設置圖書預借標志=1”是轉移伴隨的動作。
轉移還區分外部轉移和內部轉移兩種情形。
外部轉移:外部轉移是一種改變狀態的轉移。也是狀態機中常見的一種轉移。
這種轉移主要出現在兩個不同的狀態之間。
內部轉移:內部轉移是指不會導致狀態改變的轉換。有時,我們需要在該狀態下處理一些無需離開狀態的事件,這時可以定義一個內部轉移。
如“借閱圖書”這個狀態中,“超出借閱冊數”時,我們可能終止該本書的借閱,不把本書添加到借閱列表中,這種處理沒有導致借閱圖書狀態的轉移,可以視為內部轉移。
內部轉移的表示方法:
事件(參數名)[警戒條件]/動作
如下圖所示的三個event動作。
圖9 借閱圖書的狀態動作
如果源狀態與目的狀態是同一狀態,則稱為自轉移。
下面這個例子中的“循環”就是一個自轉移的例子。
圖10 自轉移
事件(Event)是指在特定時間或空間內出現,并能夠導致狀態轉移的信號、超時、條件改變、時間段等。
主要包括信號事件、時間事件、改變事件和調用事件等。
(1)信號事件
信號事件(signal event)是指一個對象接收到信號的事件,該接收信號的事件會導致其狀態的轉換。
發送對象明確地創建、初始化一個信號實例并把它發送到一個對象或對象的集合。
圖11 在選擇記錄時,按下ctrl進入多選模式狀態,釋放ctrl鍵轉換為單選模式
(2)時間事件
時間事件(time event)代表時間的流逝。當時間條件被滿足時可能要觸發某個事件。時間可以是相對的也可以絕對的。如:after(9:00)。
圖12 在路燈控制系統中,上午6:00斷電關閉,下午18:00后供電,開燈
(3)改變事件
改變事件(change event)是指依賴特定屬性值的邏輯表達式所表示的條件滿足時,事件發生。
這里的改變事件與上面所說的警戒條件不同,警戒條件是在轉移事件發生時或事件接收者對事件處理時被賦值一次,如果警戒條件為假,則轉移就不會發生,且該事件會被丟棄,警戒條件也不會再給賦值;而改變事件會被多次賦值直到條件為真,從而激活轉移??梢允褂脀hen(exp)的形式來表示。
圖13 登錄后,time自動連續增加,未操作時間超過300秒取消登錄狀態
(4)調用事件
調用事件(call event)表示一個對象接收到一個對調用的請求,這個對象用狀態的轉移而非特定的處理過程來實現操作。操作的參數即是事件的參數。調用結束時,被調用者將返回結果給調用者,調用者可以繼續執行。
圖14 借閱圖書狀態中如有未交清罰款進入到繳納罰款狀態,繳納罰款完畢后返回繳清標志,借閱圖書狀態繼續保持
動作通常是一個簡短的計算處理過程,如賦值操作或算術運算。動作也可以是一個動作序列,包括給另外一個對象發送消息、調用一個操作、設置返回值、創建或銷毀對象。
動作具有原子性,所以動作不可被中斷,不能被同時發生的其它動作所影響或終止。
動作運行時間很短,不能再被插入其它事件。
各種動作的種類及相關語法可描述如下:
(1)賦值:target:=expression
(2)調用:opname(arg1,arg2)
(3)創建對象:new Cname(arg1,arg2)
(4)銷毀對象:object.destroy()
(5)返回值:return value
(6)向對象發送消息:sname(arg1,arg2)
(7)對象自我終止:terminate
(8)不可中斷動作:[用語言說明]
在狀態圖建模過程中可以參考以下步驟:
(1)確定建模的語境
狀態機可以用于對類進行建模,也可以為一個用例進行建?;蛘邽橐粋€子系統,甚至整個系統建模。我們可以遵循從小到大的原則進行建模,從類的狀態到用例,再到子系統的過程。當然,并不是每個類都需要建立狀態機。
(2)識別狀態
確定好建模的語境后,識別其可能的狀態,識別狀態可以按照從粗到細的方法去識別。并確定出必要的狀態。
(3)確定狀態的進入動作和退出動作
對每個狀態確定其是否需要進入動作和退出動作。
(4)確定狀態中的其它動作
確定建模對象在該狀態下是否有其他需要做的事情以及警戒條件等。
(5)確定狀態之間的轉移
識別出各個狀態之間轉移的條件或事件,以及警戒條件等。
(6)檢查所繪制的狀態機是否與實際相符
(7)進行必要的優化
優化包括圖形的布局,圖形的形式,以及狀態是否有冗余等。
在Rose中,可以為一個類、一個用例或一個參與者建立狀態圖,也可以為一個子系統或整個系統建立狀態圖。
在Rose中,狀態圖可以創建在用例視圖或邏輯視圖里。
如果為某一個對象,如類、用例或參與者,可以直接在左側對象瀏覽器中的該對象上右擊,然后選擇“New”(新建)->"Statechart Diagram"(狀態圖)。
圖15 為一個對象建立狀態圖
若不指定對象,也可以在邏輯視圖或用例視圖上右擊選擇“New”->“Statechart Diagram”。
圖16 在邏輯視圖上新建狀態圖
新建完狀態圖后,可以直接給其重新命名。或者通過右擊新建的狀態圖,然后選擇“rename”,如下圖所示:
圖17 為狀態圖重命名
通過在左側對象瀏覽器中,雙擊新建的狀態圖可以開始工作了。
同時,在中間顯示出用于狀態圖的工具箱,默認的工具箱及其含義如下:
圖18 狀態圖工具箱
用戶也可以在工具箱上右擊后選擇“Customize...”來添加其它的工具,如下圖所示:
圖19 自定義工具箱
用戶可以在左側選中一個工具,然后點擊“添加(A)->”,將其添加到工具欄中,也可以把不需要的工具在右側選中之后點擊“<-刪除(R)”將其刪除掉。
在左側待選工具中,“—”是用于創建一個水平的同步條,“|”用于創建一個垂直的同步條,“◇”用于創建一個判定。
定制好自己的工具箱后,可以點擊“關閉”按鈕將其關閉。
(1)創建
用戶在工具箱中點擊狀態工具,然后在右側工作區中點擊一下,就會創建一個狀態。
(2)修改名稱
方式一:創建完狀態,其默認名稱會默認被選中,這時,用戶可以直接修改其名稱;
方式二:在創建完以后要修改其名稱,可以先選中這個狀態,然后再次點擊一下,也可以修改其名稱;
方式三:在狀態上雙擊,彈出如下對話框:
圖20 狀態圖規范說明對話框
在其“General”(通用)選項卡上的Name(名稱)項中修改其名稱;
方式四:右擊該狀態,然后選擇“Open Specification...”,也會彈出上圖所示的對話框。右擊狀態選擇的情形如下圖所示:
圖21 右擊狀態圖選擇“打開規范說明...”
(3)刪除一個狀態
如果想徹底刪除一個狀態,可以選中狀態后,按下“Ctrl + D”,這樣就把這個狀態徹底從模型庫中刪除了。
也可以在狀態上右擊,然后選擇“Edit”(編輯),再選擇“Delete from Model”,也可以把這個狀態從模型庫中徹底刪除。
用戶還可以在選中狀態后,通過菜單中的“Edit”菜單下的“Delete from Model”從模型庫中刪除該狀態。
圖22 右擊選擇刪除狀態
如果僅是從當前圖中刪除狀態,而非從模型庫中徹底刪除,用戶可以在選中狀態后,按下鍵盤上的“Del”(刪除鍵)進行刪除,也可以在狀態上右擊,然后選擇“Edit”->"Delete",如上面的圖中的Delete,也可以選擇菜單中的“Edit”->“Delete”來刪除一個狀態。
(4)為狀態添加動作
用戶可以雙擊一個狀態或右擊狀態選擇“Open Specification”打開狀態規格說明對話框。打開的狀態規范說明對話框如圖20所示。
在“General”選項卡中可以設置狀態的名稱、構造型、說明文檔、是否激活歷史狀態(淺層)或深層歷史狀態。
在第2個選項卡“Actions”中可以添加狀態的動作,如下圖:
圖23 Actions選項卡
在空白處右擊,選擇“Insert”,可以為其添加一個動作。
圖24 為狀態添加動作
添加后的動作如下圖所示:
圖25 添加動作后的效果
我們可以在動作所在的行上雙擊或右擊后選擇“Specification...”,其會彈出如下圖所示的對話框:
圖26 動作的規格說明
在該對話框中的“When”對應的下拉列表中可以設置動作的類型,其中“On Entry”代表進入動作,“On Exit”代表退出動作,“Do”代表內部執行的活動,“On Event”代表內部事件轉移。Type用于指定動作的類型是一個普通動作(Action)還是發送一個事件(Send Event)。
當“When”中選擇的是“On Event”時,在“When”下邊的“On Event”分組框中可以設置事件的名稱、參數和條件。
下圖是On Event的一個設置情景:
圖27 動作規格說明的例子
下圖是對“已借出”狀態設置的相關動作。
圖28 設置了動作的狀態規格說明
在工具相中選擇“狀態轉移”工具,鼠標會變為一個向上的空心箭頭的形狀,這時,在源狀態上按下鼠標不放,滑動到目的狀態上后松開鼠標即可。
下圖給出了鼠標到達目的狀態松開之前的一個情景。
圖29 添加狀態的轉移
松開鼠標之后的效果如下圖所示:
圖片
圖30 添加了狀態轉移后的樣子
設置轉移的相關內容
方式一:選中轉移后,右擊后選擇“Open Specification...”,如下圖所示:
圖31 右鍵打開轉移的規格說明
方式二:雙擊轉移。
兩種方式都會打開下圖所示的狀態轉移規格說明對話框:
圖32 轉移的規格說明——General
在上面圖中“General”選項卡的Event行中添加觸發轉移的事件,在Arguments行中添加事件的參數。
在“Detail”選項卡中可以對觸發事件進行詳細的設置,如下圖:
圖33 轉移個規格說明——Detail
設置的內容包括“Guard Condition(警戒條件)”、“Action(動作)”以及發送的事件、發送事件的參數和發送的目標對象。
若在General和Detail設置的內容如圖34和圖35中的樣子,則最后在源狀態和目的狀態中呈現的樣子如圖36所示:
圖34 轉移規格說明例子——General設置
圖35 轉移的規格說明——Detail設置
圖36 狀態轉移設置的最終樣子
在添加了主狀態之后,可以在其主狀態中,添加子狀態,方法是在工具箱中選擇狀態后,直接在主狀態上點擊即可,則在主狀態中會添加一個子狀態。
下圖顯示了當選擇狀態工具后,鼠標滑到主狀態上時的情形:
圖37 添加子狀態
下圖顯示了添加完后的情形:
圖38 子狀態效果
給子狀態添加轉移等方法與上面有關內容相同。
打開狀態的規格說明對話框(雙擊狀態或右擊選擇“Open Specification...”),在“General”選項卡中把下面的“State/activity history”勾選上,則會在狀態的左下角顯示一個帶圈的H,如果想激活狀態的深層歷史狀態,就把“Sub state/activity history”也勾選上,則原來H字母的右上角出現一個“*”號。
設置歷史狀態的情形如下:
圖39 設置歷史狀態
狀態設置后的效果如下圖所示:
圖40 歷史狀態
用戶可以使用本文中4.2中的方法,把水平同步條以及垂直同步條添加到工具箱中,在需要的時候選擇它后并在繪圖區點擊一下,即可以添加一個同步條。
用戶也可以通過菜單欄中的“Tools”->“Create”中的“Horizontal Synchronization Bar”及“Vertical Synchronization Bar”創建水平同步條或垂直的同步條。如下圖所示的菜單:
圖41 使用菜單添加同步條
若要創建初始狀態,用戶可以直接在工具箱中選擇黑色的實心圓,在繪圖區點擊一下就可以創建一個初始狀態。
注意:一個狀態圖中只允許有一個初始狀態,如果在一個繪圖區中要使用多次初始狀態,用戶可以從左側瀏覽器中把它拖拽到繪圖區 中來。
創建結束狀態的方法與創建初始狀態的方法相同。
在一個狀態圖中,可以有多個結束狀態。
以上帶大家學習了UML中的狀態機圖以及使用Rose繪制狀態圖的方法。
如有問題,請留言。
新聞熱點
疑難解答