複製鏈接
請複製以下鏈接發送給好友

狀態圖

鎖定
狀態圖(Statechart Diagram)是描述一個實體基於事件反應的動態行為,顯示了該實體如何根據當前所處的狀態對不同的事件做出反應。通常我們創建一個UML狀態圖是為了以下的研究目的:研究類、角色子系統、或組件的複雜行為
中文名
狀態圖
外文名
State Diagram
基    於
事件反應
動態建模
事件驅動的方面
目    的
研究類、角色
用    於
顯示狀態

狀態圖基本介紹

狀態圖用於顯示狀態機(它指定對象所在的狀態序列)、使對象達到這些狀態的事件和條件、以及達到這些狀態時所發生的操作。 [1] 

狀態圖動態建模

狀態機用於對模型元素的動態行為進行建模,更具體地説,就是對系統行為中受事件驅動的方面進行建模(請參見概念:事件與信號)。狀態機專門用於定義依賴於狀態的行為(即根據模型元素所處的狀態而有所變化的行為)。其行為不會隨着其元素狀態發生變化的模型元素不需要用狀態機來描述其行為(這些元素通常是主要負載管理數據的被動類)。
圖 1:狀態機符號。 圖 1:狀態機符號。
狀態機由狀態組成,各狀態由轉移鏈接在一起。狀態是對象執行某項活動或等待某個事件時的條件。轉移是兩個狀態之間的關係,它由某個事件觸發,然後執行特定的操作或評估並導致特定的結束狀態。圖 1 描繪了狀態機的各種元素。一個簡單的編輯器可被視為有限的狀態機,其狀態為Empty(空)、Waiting for a command(等待命令)和 Waiting for text(等待文本)。事件 Load file(裝載文件)、Insert text(插入文本)、Insert character(插入字符)和Saveandquit(保存並退出)導致了狀態機中的轉移。下面的圖 2 描繪了編輯器狀態機 [2] 
圖 2:簡單編輯器的狀態機。 圖 2:簡單編輯器的狀態機。

狀態圖狀態

狀態是對象執行某項活動或等待某個事件時的條件。對象可能會在有限的時間長度內保持某一狀態。狀態具有以下幾項特徵:
名稱
將一個狀態與其他狀態區分開來的文本字符串;狀態也可能是匿名的,這表示它沒有名稱。
進入/退出操作
在進入和退出狀態時所執行的操作。
內部轉移
在不使狀態發生變更的情況下進行的轉移。
子狀態
狀態的嵌套結構,包括不相連的(依次處於活動狀態的)或並行的(同時處於活動狀態的)子狀態。
延遲的事件
未在該狀態中處理但被延遲處理(即列隊等待由另一個狀態中的對象來處理)的一系列事件。

狀態圖轉移

轉移是兩個狀態之間的關係,它表示當發生指定事件並且滿足指定條件時,第一個狀態中的對象將執行某些操作並進入第二個狀態。當發生這種狀態變更時,即“觸發”了轉移。在觸發轉移之前,可認為對象處於“源”狀態;在觸發轉移之後,可認為對象處於“目標”狀態。轉移具有以下幾項特徵:
源狀態
轉移所影響的狀態;如果對象處於源狀態,當對象收到轉移的觸發事件並且滿足警戒條件(如果有)時,就可能會觸發輸出轉移。
事件觸發器
使轉移滿足觸發條件的事件。當處於源狀態的對象收到該事件時(假設已滿足其警戒條件),就可能會觸發轉移。
警戒條件
一種布爾表達式。在接收到事件觸發器而觸發轉移時,將對該表達式求值;如果該表達式求值結果為 True,則説明轉移符合觸發條件;如果該表達式求值結果為 False,則不觸發轉移。如果沒有其他轉移可以由同一事件來觸發,該事件就將被丟棄。
操作
可執行的、不可分割的計算過程,該計算可能直接作用於擁有狀態機的對象,也可能間接作用於該對象可見的其他對象。
目標狀態
在完成轉移後被激活的狀態。
一個轉移可能有多個源狀態,在這種情況下,它將呈現為一個從多個並行狀態出發的結合點;一個轉移也可能有多個目標狀態,在這種情況下,它將呈現為一個到多個併發狀態的叉形圖。

狀態圖事件觸發器

在狀態機環境中,事件是指可觸發狀態轉移的激勵的發生。事件可能包括信號、調用、時間推移或狀態變更。信號或調用可能具有其值可用於轉移的參數,其中包括警戒條件和操作的表達式。也可能會有無觸發器的轉移,這樣的轉移沒有事件觸發器。這種轉移也被稱為完成轉移,它們在源狀態完成其活動後將被隱含觸發。

狀態圖警戒條件

當轉移的觸發事件發生時,將對警戒條件進行求值。只要警戒條件不重疊,就可能會有來自同一源狀態並具有同一事件觸發器的多個轉移。在事件發生時,只為轉移進行一次警戒條件求值。該布爾表達式可能會引用對象的狀態。

狀態圖操作

操作是可執行的、不可分割的計算過程,這意味着,它不會被事件中斷,而會一直運行到結束為止。它與活動正好相對,因為活動可能被其他事件中斷。操作可以包括操作調用(調用狀態機的擁有者以及其他可見對象)、創建或破壞其他對象、或者向另一個對象發送信號。在發送信號的情況下,信號名稱以關鍵字“send”為前綴。

狀態圖進入退出操作

每當進入或退出狀態時,進入和退出操作將分別允許發出同一操作。這可以通過進入和退出操作來順利地完成,而不必明確地將操作放在每個輸入或輸出轉移上。進入和退出操作可能沒有實參或警戒條件。位於模型元素的狀態機頂層的進入操作可能具有特定的參數,這些參數代表了在創建該模型元素時狀態機所接收到的實參。

狀態圖內部轉移

內部轉移使事件可以在不退出狀態的情況下在狀態內得到處理,從而可避免觸發進入或退出操作。內部轉移可能會有帶參數和警戒條件的事件,它們所代表的基本上是中斷處理程序。

狀態圖延遲的事件

延遲的事件是其處理過程被推遲的事件,它們的處理過程要到事件不被延遲的狀態被激活時才會執行。當該狀態被激活時,將觸發該事件,同時可能導致轉移(好象該事件剛剛發生)。要實施延遲的事件,需要有事件的內部隊列。如果事件已發生但被列為延遲,它就會被添加到隊列中。當對象進入了不會使事件延遲的狀態時,將立即從該隊列中取出這些事件。

狀態圖子狀態

圖 3:子狀態 圖 3:子狀態
簡單狀態是沒有子結構的狀態。具有子狀態(嵌套狀態)的狀態被稱為複合狀態。子狀態可能被嵌套到任意級別。嵌套的狀態機最多可能有一個初始狀態和一個終止狀態。通過顯示某些狀態只能在特定環境(包含狀態)中存在,子狀態可以簡化複雜的平面狀態機。
轉移的源狀態是包含複合狀態之外的源狀態,其目標狀態可能是複合狀態或子狀態。如果其目標狀態是複合狀態,嵌套的狀態機就必須包括一個初始狀態,在進入複合狀態之後並在發出它的進入操作(如果有)之後,控制權將被傳遞給該初始狀態。如果其目標狀態是嵌套狀態,那嵌套狀態的進入操作(如果有)後,控制權將被傳遞給該嵌套狀態。
從複合狀態出發的轉移可能會以複合狀態或子狀態作為它的源狀態。在這兩種情況下,控制權先離開嵌套狀態(並在可能的情況下發出它的退出操作),然後離開復合狀態(並在可能的情況下發出它的退出操作)。其源狀態為複合狀態的轉移基本上會中斷嵌套狀態機的活動。 [1] 

狀態圖歷史狀態

圖 4:歷史狀態 圖 4:歷史狀態
除非另有指定,當轉移進入複合狀態時,嵌套狀態機的操作將從初始狀態開始重新執行(除非轉移直接以子狀態為目標)。歷史狀態使狀態機可以重新進入在它退出複合狀態之前的最後一個活動子狀態。圖 4 顯示瞭如何使用歷史狀態的示例。 [3] 

狀態圖建模技術

狀態機最多地用於建立對象在其生命期內的行為模型。當對象具有依賴於狀態的行為時,尤其需要使用狀態機。可能具有狀態機的對象包括:類、子系統、用例、接口(以聲明實現該接口的對象必須滿足的狀態)和協議(以聲明實現該協議的對象必須滿足的狀態)。並非所有對象都需要有狀態機。如果對象的行為很簡單,只是存儲或檢索數據,那麼該對象的行為就與狀態無關,它的狀態機也沒有多少用處。
要建立對象生命期的模型,需要包括三個事項:指定對象可以響應的事件、指定對這些事件作出的響應以及指定過去行為對當前行為的影響。對象生命期的建模還涉及到確定對象有意義地響應事件的順序,即從創建對象時開始,繼續到該對象被破壞時為止。
要建立對象生命期的模型:
將狀態機的環境設置為類、用例或整個系統。
如果環境是類或用例,則要收集相鄰的類,其中包括父類或通過關聯關係或依賴關係可以接觸到的類。這些相鄰類是操作的候選目標,並且是可以包括在警戒條件中的候選目標。
如果環境是整個系統,則要將重點集中到系統的一個行為上,然後考慮在該方面涉及到的對象的生命期。整個系統的生命期通常會大得無法成為有意義的重點。
確定對象的初始狀態和終止狀態。如果初始和終止狀態具有前提條件和後續條件,也應將這些條件定義出來。
確定對象要響應的事件。這些事件可以在對象的接口或協議中找到。
按照從初始狀態到終止狀態的順序,列出對象可能處於的頂層狀態。將這些狀態與相應事件所觸發的轉移連接起來。然後添加這些轉移。
確定所有進入操作或退出操作。
通過使用子狀態來擴展或簡化狀態機。
檢查狀態機中的所有事件觸發轉移是否與該對象實現的接口或協議所期望的事件相符。同樣,檢查對象的接口或協議所期望的所有事件是否都得到了狀態機的處理。最後,確定要在哪些地方明確地忽略事件(如延遲的事件)。
檢查狀態機中的所有操作是否都得到了包含對象的關係、方法和操作的支持。
跟蹤狀態機,將它與事件及其響應的預期序列進行比較。搜索無法達到的狀態以及狀態機無法繼續向前的狀態。
如果要重新佈置或重新構建狀態機,需檢查並確保語義沒有發生變更。 [3] 

狀態圖提示與技巧

當給定一項選擇時,要使用狀態機的可視語義,而不要寫出詳細的轉移代碼。例如,不要用幾個信號觸發一個轉移,然後使用詳細代碼來管理以不同的方式依賴於信號的控制流。應使用由單獨的信號來觸發的單獨轉移。在隱藏了附加行為的轉移代碼中,要避免使用條件邏輯。
根據在狀態期間等待的事件或正在發生的事件來命名狀態。記住,狀態不是“時間點”;它是狀態機等待某個事件發生的時間段。例如,“waitingForEnd”這一名稱比“end”更好;“timingSomeActivity”比“timeout”更好。不要讓狀態的名稱看起來象是操作名。
在一個狀態機內唯一地命名所有狀態和轉移;這將便於進行源級別的調試。
謹慎使用狀態變量;不要在創建新狀態時使用它們。如果狀態不多,很少帶有或不帶有依賴於狀態的行為,並且很少有或根本沒有可能與包含狀態機的封裝體並行或獨立的行為,就可以使用狀態變量。如果有複雜的、依賴於狀態的潛在並行行為,或者如果必須處理的事件可能來自於包含狀態機的封裝體之外,則應考慮使用構件封裝體。
如果單個圖中的狀態超過 5 * 2 個,就應考慮使用子狀態。在這裏可以應用我們的常識:在一個非常規則的模式中可以有十個狀態,但如果兩個狀態之間具有四十個轉移,顯然就需要重新考慮了。務必要使狀態機易於理解。
使用觸發事件的事件和/或在轉移期間發生的事件為轉移命名。選擇更加易於理解的名稱。
當您看見一個選擇點時,應考慮是否可以將作出該選擇的職責委託給另一個構件,以便將其作為一組將不同的信號提供給封裝體遵照執行(例如,代替對消息->數據 > x 的選擇),並考慮是否可以讓發送方或另一中間主角來作出決定,然後通過在信號名稱中明確顯示該決定的方式發送信號(例如,使用名為 isFull 和 isEmpty 的信號,而不是以值命名信號並檢查消息數據)。
為在選擇點中回答的問題指定描述性的名稱,例如“isThereStillLife”或“isItTimeToComplain”。
在任何給定的封裝體中,儘量使選擇點名稱保持唯一(其原因與轉移名稱需保持唯一相同)。
轉移的代碼段是否太長?是否應使用函數來代替它們,是否將常用代碼段記錄為函數?轉移應該類似於高層的偽代碼,並且應當遵循與 C++ 函數相同或更嚴格的長度規則。例如,代碼超過 25 行的轉移可被認為是過長。
應根據函數執行的操作來命名函數。
要特別注意進入和退出操作:在進行更改後忘記更改相應進入和退出操作的情況尤其容易發生。
退出操作可用於提供安全性功能,例如,從“heaterOn”狀態中的退出操作將關閉加熱器,在這裏,操作被用來強制執行一個斷言語句。
通常,除非狀態機是抽象的並且將由包含元素的子類來進行改進,否則子狀態應包含兩個或更多個狀態。
應該用選擇點來代替操作或轉移中的條件邏輯。選擇點容易被看到,而代碼中的條件邏輯則是不可見的,很容易被忽略。
避免使用警戒條件。
如果事件觸發了幾個轉移,將無法控制首先對哪個警戒條件求值。這會產生無法預料的結果。
可能有多個警戒條件為“True”,但隨後只能有一個轉移。所選擇的路徑是無法預料的。
警戒條件是不可見的;要“看見”它們的出現更是困難。
避免使用類似流程圖的狀態機。
這可能表示您試圖對並不實際存在的抽象概念進行建模,例如:
使用一個封裝體來對最適合於數據類的行為進行建模,或
通過使用緊密耦合的數據類和封裝體類來對數據類建模(例如,數據類用於向四周傳遞類型信息,但封裝體類包含了應與數據類相關聯的大部分數據)。
狀態機的這種錯誤用法可以通過以下故障現象來識別:
被髮送給“自己”的消息,主要是為了重複使用代碼
幾乎沒有狀態,但有很多選擇點
在某些情況下沒有循環的狀態機。在流程控制應用程序中,或者在試圖控制一個事件序列時,這樣的狀態機是有效的;如果它們在分析過程中出現,則表示狀態機已退化為流程圖。
當發現問題時,應採取以下措施:
考慮將封裝體分解為職責更明確的小單元,
將更多的行為轉移到與有問題的封裝體相關聯的數據類中。
將更多的行為轉移到封裝體類函數中。
製作更有意義的信號,以避免對數據的依賴。
使用抽象狀態機進行設計
圖 5:一個抽象狀態機 圖 5:一個抽象狀態機
抽象狀態機是需要添加更多細節才能實際使用的狀態機。抽象狀態機可用於定義可複用的一般行為,這些行為將在隨後的模型元素中得到進一步的改進。請考慮圖 5 中的抽象狀態機。例如,圖 5 中的簡單狀態機代表了實時系統中許多不同元素類型的最抽象的行為(自動“控制”)。儘管不同的元素類型都具有這一最高抽象程度,但是,根據其目的,它們可能在“Running”狀態中具有非常不同的詳細行為。因此,該狀態機最有可能在某個抽象封裝體類中定義,該封裝體類被用作不同的專用封裝體類的根類。 [4] 
因此,我們將使用繼承來定義該抽象狀態機的兩種不同的改進形式。圖 6 顯示了這兩種改進形式 R1 和 R2。為清晰起見,我們使用淺灰筆來描繪從父類繼承而來的元素。
這兩種改進形式的明顯差異在於它們分解“Running”(正在運行)狀態的方式,以及它們擴展原“start”(開始)轉移的方式。當然,只有當改進形式已知,因而未在抽象類中使用單個端到端轉移來實施時,才能作出這些選擇。

狀態圖鏈式狀態

對於上述的改進類型而言,能夠同時“繼續”輸入轉移和輸出轉移是基本的能力。結合使用進入點、終止狀態和繼續轉移似乎就足以提供這些語義。但是,如果有多個不同的轉移需要擴展,這就行不通了。
圖6:圖5 中狀態機的兩種改進形式 圖6:圖5 中狀態機的兩種改進形式
在這種情況下,抽象行為模式需要的是用一種方法把在單個運行至結束的步驟中全部執行的兩個或更多個轉移段鏈接起來。這意味着,要將進入分層結構狀態的轉移拆分成一個在狀態邊界處有效終止的進入部分,以及一個在狀態內繼續的擴展部分。同樣,將分層嵌套的狀態所發出的輸出轉移分為一個在包含狀態邊界處終止的部分,以及一個從狀態邊界繼續到目標狀態的部分。通過引入鏈式狀態的概念,可以在 UML 中獲得這一效果。它通過 UML 狀態概念的原型 («chainState») 來建模。該狀態的唯一目的是將更多的自動(無觸發器)轉移“鏈接”到輸入轉移上。鏈式狀態沒有內部結構:沒有進入操作,沒有內部活動,沒有退出操作。它也沒有由事件觸發的轉移。但它可以有任意數量的輸入轉移。鏈式狀態可能有不帶觸發事件的輸出轉移;當輸入轉移激活鏈式狀態時,該轉移將自動觸發。這種狀態的目的是將輸入轉移鏈接到獨立的輸出轉移上。在輸入轉移和被鏈接的輸出轉移之間,一個狀態連接到包含狀態內部的另一個狀態,而該狀態又連接到包含狀態外部的另一個狀態。引入鏈式狀態的目的是將包含狀態的內部規約與其外部環境分隔開,這也是一種封裝。
實際上,鏈式狀態代表的是一種“串通”狀態,它用於將某個轉移鏈接到一個特定的繼續轉移。如果沒有定義繼續轉移,轉移就會在鏈式狀態中終止。要使操作繼續,就必須觸發包含狀態中的某一轉移。
圖 7. 鏈式狀態和被鏈接的轉移 圖 7. 鏈式狀態和被鏈接的轉移
圖 7 中的示例狀態機段顯示了鏈式狀態及其符號。鏈式狀態在狀態機圖中表示為在適當分層結構狀態內的白色小圓(該符號類似於與它們相似的初始狀態和終止狀態)。圓是鏈式狀態原型的原型圖標,為了方便,通常把它們描繪在邊界附近。(實際上,另一種標誌法是把它們描繪在包含狀態的邊界上,類似於封裝體上的端口符號。)
該示例中,被鏈接的轉移包括三個被鏈接的轉移段 (e1/a11-/a12-/a13)。當收到信號 e1 時,將調用標記為 e1/a11 的轉移,執行它的操作 a11,然後進入鏈式狀態 c1。接着,調用 c1 和 c2 之間的繼續轉移。最後,由於 c2 也是鏈式狀態,所以從 c2 轉移到 S21。如果沿這些路徑的狀態都有退出和進入操作,那麼實際的操作執行順序將是:
S11 的退出操作
操作 a11
S1 的退出操作
操作 a12
S2 的進入操作
操作 a13
S21 的進入操作
以上所有操作都將在單個運行至結束的步驟中執行。
應將這些操作與直接轉移 e2/a2 的操作執行語義進行對比,後者是:
S11 的退出操作
S1 的退出操作
操作 a2
狀態 S2 的進入操作
狀態 S21 的進入操作 © 1987 - 2001RationalSoftware Corporation。版權所有。

狀態圖通用準則

當行為的改變和狀態有關時才創建狀態圖。
敏捷建模(AM) ( Ambler 2002)的原則--最大化項目干係人的投資--建議你只有當模型能夠提供正面價值的時候才創建模型。 如果一個實體,比如一個類或組件,表示的行為的順序和當前的狀態無關,那麼畫一個UML狀態圖可能是沒有什麼用處的。例如一個SurfaceAddrESs類就很簡單,表示了那些你將會在系統中顯示和操作的數據,因此一個UML狀態圖就沒有任何相關之處。而一個Seminar對象就非常的複雜,學生註冊這樣一個事件將會根據它的當前狀態有不同的反應,就像你在圖1中看到的。 [5] 
圖⒈班級註冊的一個UML狀態圖。 圖⒈班級註冊的一個UML狀態圖。
把初始狀態放置在左上角。
如你在圖1所見的,初始狀態被建模成一個實心圈,把初始狀態放在左上角反映西方人的閲讀文化的習慣。
把最終狀態放置在右下角。
如你在圖1所見,最終狀態被建模為一個帶邊界的實心圓。把最終狀態放右下角反映了西方的文化的從左到右,從上到下的閲讀習慣。

狀態圖狀態指南

狀態是一個實體的行為模式的某個階段。 狀態的表示是通過實體的屬性值。 例如,在圖1中,當seminar被標記為open,並且存在空位的時候,seminar就處於Open For Enrollment的狀態。
狀態名稱要簡單但應具有描述性。
象Open For Enrollment和PropOSed這種的狀態名稱很容易理解,從而提高了圖⒈的溝通價值。理論上狀態名稱應該是現在時,但是用過去式寫成的諸如Proposed的名稱要比用現在時寫成的諸如Is Proposed的名稱好的多。
避免"黑洞"狀態。
黑洞狀態是那種只有變換進來但沒有任何變換髮出的狀態,這種情況要麼由於該狀態是一個最終狀態,要麼就是你已經錯過了一個或多個變換變換。
避免"奇蹟"狀態。
奇蹟狀態是那種只有變換髮出但沒有任何變換進來的狀態,這種情況要麼由於該狀態是一個起點,要麼就是你已經錯過了一個或多個變換變換。

狀態圖建模指南

狀態圖建模子狀態

圖1中展示的UML狀態圖是不完整的,因為它沒有建模Seminar的poST - enrollment(註冊後)狀態。 圖2建模了一個Seminar的完整的生命週期,把圖1描述為一個新的包括子狀態集合的Enrollment的複合狀態,也稱作超狀態。 注意按理説你會像圖1的模型那樣處理標記,但為了簡化起見在原先變換上的標記都沒有包括在內。當一個現有狀態表現出複雜的行為時,建模子狀態就是有意義的,從而促使你來研究它的子狀態。 當幾個現有狀態共用一個通用的入口條件或出口條件( DouglASs 1999)時,引入超狀態是有意義的,在圖1中你可以看到所有的狀態共用一個通用的closed變換,以到達最終狀態。

狀態圖子狀態變換

和圖1中每一個子狀態都擁有一個cancelled變換不同,在圖2中你可以看到cancelled變換僅用於描述Enrollment超狀態,這使圖形得到簡化。 如果子狀態都共享一個入口變換或出口變換,都可以使用一個同樣的方法。 變換上的警戒點和動作(如果有)也應該使相等的。
為複雜的實體創建一個分層的狀態圖
雖然這種表現子狀態的方法是很好使的,但是最終的圖可能變得相當複雜--我們只要設想一下如果Being Taught狀態也有子狀態的話,圖2會變成什麼樣就知道了。 一個替代的方法是創建一個分層的UML狀態圖。 例如,圖3表示高階視圖,而圖1描述了一個細節視圖。這種方法的好處是如果需要的話,馬上就可以建立一張詳圖來研究Being Taught狀態。
最高階的狀態圖總有初始態和最終態
一個高階的UML狀態圖,例如圖2描述的這樣,應該表示實體的完整的生命週期,包括"出生"和最後的"死亡"。 低階的圖未必包含初始狀態和最終狀態,特別是那些建模一個實體的生命週期的"中間狀態"的圖。

狀態圖變換和動作

變換是從一種狀態到另一種狀態的序列,它可能是通過一個事件觸發的。簡而言之就是被建模的實體的內部或外部的行為。 對一個類來説,變換一般是將會導致狀態的重要改變的操作調用的結果,因此我們需要了解一點,並不是所有的方法調用都會導致變換產生的,這一點非常重要。 一個動作就是某個東西,對類來説就是一個操作,被建模的實體所調用的操作。
用實現語言的命名規則命名軟件動作
圖1中的動作遵循Java操作的命名規則( Vermeulen et. 2000),因為系統使用
用敍述性文字命名角色動作
UML狀態圖可用於建模非軟件實體的生命週期,特別是UML圖上的角色。 例如學生角色就可能有諸如Accepted、Full Time、Part Time、Graduated、Masters、Doctoral、和Post - Doctoral等狀態,以顯示各人的不同行為。 當你在建模現實世界的角色時,與軟件中Student類不同的是,狀態間的變換最好是使用敍述性文字來描述,例如drop seminar和pay fees,而不是dropSeminar ()和payFees (),因為現實生活中的人是做事情,而不是執行操作。
只有對所有的入口變換都合適時才註明入口動作
在圖1中你可以看到Closed To Enrollment狀態的入口中操作notifyInstructor ()都是經由entry/動作標記來調用的。 這暗示着每次進入狀態時都需要調用該操作,如果你不希望每次都發生,那麼就把動作關聯到特定的入口變換。 例如,addStudent ()動作是在student enrolled變換到Open For Enrollment變換髮生,而在到opened變換則不會發生,這是因為每次你在進入該狀態並不需要增加一個學生。
只有對所有的出口變換適合時才註明出口動作
出口動作,用exit/標記來表示,工作方式類似於入口動作。
只有當你想終止並再進入該狀態時才建模遞歸變換
一個遞歸的變換是那些兩個端點都擁有相同狀態的變換。 一個重要的暗示是實體從狀態出來,又回到原有的狀態,因此,那些由於entry/或exit/動作標記而被調用的任何一種操作都可能被自動調用。 圖1的Open For Enrollment狀態就是這種遞歸變換的例子,因此當前班級大小就在入口處被記錄下來。
用過去式命名轉換事件
圖1中的轉換事件,例如seminar split和cancelled,是使用過去式命名的,反映了這樣一個事實:變換是事件的結果--因為事件發生在變換之前,因此應該用過去式命名。
把轉換標記放在接近源狀態的地方
雖然圖1比較複雜,變換標記儘可能放在靠近來源的地方,例如seminar split和student enrolled。 Furthermore, the labels were justified (left and right respECtively) to help visually place them close to the source state.
為了更易於判斷哪個標記和變換是一起的,按照如下的規則來放置變換標記:
在變換線條上的從左到右。
在變換線條下的從右到左。
變換線條右邊的往下。
變換線條左邊的往上。
警戒點 一個警戒點是為了穿過一個轉換而必須為真的一個條件。
警戒點不應該重疊
離開狀態的相似變換上的警戒點必須彼此一致。 舉例來説,x <0, x = 0,以及x > 0的警戒點是一致的,而x < = 0和x > = 0的警戒點就不是一致的,因為他們重疊了,它並沒有明確的指出當x為0時將發生什麼。在圖1中,你可以看到警界點的一致性,從填寫註冊表活動出發的該學生劃線變換上的警戒點沒有重疊,決策點上的警戒點也一樣。
為可視化的定位警戒點而引入接合點。
在圖2中你可以看到從Being Taught觸發student dropped事件存在兩個變換,而圖3中僅有一個,變換被合併了,因此我們需要一個接合點(填滿的圓)。 這種方法的好處是現在圖上的兩個警戒點更彼此接近了,更容易看出警戒點是否重疊。
警戒點不必配套
一個狀態的變換警戒點有可能是不完整的。例如,一個bank account對象可能從Open狀態變換到Needs Authorization狀態,這時需要一個大額存款"large deposit"的警戒點。可是,一個帶有"small deposit"的警戒點的deposit變換可能並不需要建模,它是被隱含的,我們遵循了AM的實踐--簡單的描述模型和僅僅包括相關的信息。
一致的命名警戒點
圖1包含了諸如seat avAIlable和no seat available的警戒點,兩個警戒點的描述是一致的。 然而,諸如seats left、no seat left、no seats left、no seats available、seat unavailable之類的描述就是不一致,而且難於理解的。
參考資料
  • 1.    趙也非. 動態UML子圖的形式語義研究[D]. 華東師範大學, 2010.
  • 2.    劉徵. 基於UML-NuSMV的聯鎖軟件形式化建模與驗證[D].
  • 3.    黃吉亞. 狀態圖到C++上的映射方法研究[D]. 昆明理工大學, 2009.
  • 4.    單錦輝, 張路, 王金波, et al. 實時嵌入式軟件時間抽象狀態機的擴展[J]. 北京大學學報(自然科學版), 2019, 55(2):197-208.
  • 5.    鄧蓉蓉. 基於敏捷建模方法的軟件需求分析研究[D]. 武漢理工大學, 2009.