狀態(tài)圖(Statechart Diagram)是描述一個實體基于事件反應的動態(tài)行為,顯示了該實體如何根據(jù)當前所處的狀態(tài)對不同的時間做出反應的。通常我們創(chuàng)建一個UML狀態(tài)圖是為了以下的研究目的:研究類、角色、子系統(tǒng)、或組件的復雜行為。
狀態(tài)圖用于顯示狀態(tài)機(它指定對象所在的狀態(tài)序列)、使對象達到這些狀態(tài)的事件和條件、以及達到這些狀態(tài)時所發(fā)生的操作。
狀態(tài)機用于對模型元素的動態(tài)行為進行建模,更具體地說,就是對系統(tǒng)行為中受事件驅動的方面進行建模(請參見概念:事件與信號)。狀態(tài)機專門用于定義依賴于狀態(tài)的行為(即根據(jù)模型元素所處的狀態(tài)而有所變化的行為)。其行為不會隨著其元素狀態(tài)發(fā)生變化的模型元素不需要用狀態(tài)機來描述其行為(這些元素通常是主要負載管理數(shù)據(jù)的被動類)。
狀態(tài)機由狀態(tài)組成,各狀態(tài)由轉移鏈接在一起。狀態(tài)是對象執(zhí)行某項活動或等待某個事件時的條件。轉移是兩個狀態(tài)之間的關系,它由某個事件觸發(fā),然后執(zhí)行特定的操作或評估并導致特定的結束狀態(tài)。圖 1 描繪了狀態(tài)機的各種元素。

一個簡單的編輯器可被視為有限的狀態(tài)機,其狀態(tài)為 Empty(空)、Waiting for a command(等待命令)和 Waiting for text(等待文本)。事件 Load file(裝載文件)、Insert text(插入文本)、Insert character(插入字符)和 Save and quit(保存并退出)導致了狀態(tài)機中的轉移。下面的圖 2 描繪了編輯器的狀態(tài)機。

狀態(tài)
狀態(tài)是對象執(zhí)行某項活動或等待某個事件時的條件。對象可能會在有限的時間長度內保持某一狀態(tài)。狀態(tài)具有以下幾項特征:

轉移
- 事件觸發(fā)器
- 警戒條件
- 操作
- 進入和退出操作
- 內部轉移
- 延遲的事件
轉移是兩個狀態(tài)之間的關系,它表示當發(fā)生指定事件并且滿足指定條件時,第一個狀態(tài)中的對象將執(zhí)行某些操作并進入第二個狀態(tài)。當發(fā)生這種狀態(tài)變更時,即“觸發(fā)”了轉移。在觸發(fā)轉移之前,可認為對象處于“源”狀態(tài);在觸發(fā)轉移之后,可認為對象處于“目標”狀態(tài)。轉移具有以下幾項特征:

一個轉移可能有多個源狀態(tài),在這種情況下,它將呈現(xiàn)為一個從多個并行狀態(tài)出發(fā)的結合點;一個轉移也可能有多個目標狀態(tài),在這種情況下,它將呈現(xiàn)為一個到多個并發(fā)狀態(tài)的叉形圖。
事件觸發(fā)器
在狀態(tài)機環(huán)境中,事件是指可觸發(fā)狀態(tài)轉移的激勵的發(fā)生。事件可能包括信號、調用、時間推移或狀態(tài)變更。信號或調用可能具有其值可用于轉移的參數(shù),其中包括警戒條件和操作的表達式。也可能會有無觸發(fā)器的轉移,這樣的轉移沒有事件觸發(fā)器。這種轉移也被稱為完成轉移,它們在源狀態(tài)完成其活動后將被隱含觸發(fā)。
警戒條件
當轉移的觸發(fā)事件發(fā)生時,將對警戒條件進行求值。只要警戒條件不重疊,就可能會有來自同一源狀態(tài)并具有同一事件觸發(fā)器的多個轉移。在事件發(fā)生時,只為轉移進行一次警戒條件求值。該布爾表達式可能會引用對象的狀態(tài)。
操作
操作是可執(zhí)行的、不可分割的計算過程,這意味著,它不會被事件中斷,而會一直運行到結束為止。它與活動正好相對,因為活動可能被其他事件中斷。操作可以包括操作調用(調用狀態(tài)機的擁有者以及其他可見對象)、創(chuàng)建或破壞其他對象、或者向另一個對象發(fā)送信號。在發(fā)送信號的情況下,信號名稱以關鍵字“send”為前綴。
進入和退出操作
每當進入或退出狀態(tài)時,進入和退出操作將分別允許發(fā)出同一操作。這可以通過進入和退出操作來順利地完成,而不必明確地將操作放在每個輸入或輸出轉移上。進入和退出操作可能沒有實參或警戒條件。位于模型元素的狀態(tài)機頂層的進入操作可能具有特定的參數(shù),這些參數(shù)代表了在創(chuàng)建該模型元素時狀態(tài)機所接收到的實參。
內部轉移
內部轉移使事件可以在不退出狀態(tài)的情況下在狀態(tài)內得到處理,從而可避免觸發(fā)進入或退出操作。內部轉移可能會有帶參數(shù)和警戒條件的事件,它們所代表的基本上是中斷處理程序。
延遲的事件
延遲的事件是其處理過程被推遲的事件,它們的處理過程要到事件不被延遲的狀態(tài)被激活時才會執(zhí)行。當該狀態(tài)被激活時,將觸發(fā)該事件,同時可能導致轉移(好象該事件剛剛發(fā)生)。要實施延遲的事件,需要有事件的內部隊列。如果事件已發(fā)生但被列為延遲,它就會被添加到隊列中。當對象進入了不會使事件延遲的狀態(tài)時,將立即從該隊列中取出這些事件。
子狀態(tài)
簡單狀態(tài)是沒有子結構的狀態(tài)。具有子狀態(tài)(嵌套狀態(tài))的狀態(tài)被稱為復合狀態(tài)。子狀態(tài)可能被嵌套到任意級別。嵌套的狀態(tài)機最多可能有一個初始狀態(tài)和一個終止狀態(tài)。通過顯示某些狀態(tài)只能在特定環(huán)境(包含狀態(tài))中存在,子狀態(tài)可以簡化復雜的平面狀態(tài)機。

轉移的源狀態(tài)是包含復合狀態(tài)之外的源狀態(tài),其目標狀態(tài)可能是復合狀態(tài)或子狀態(tài)。如果其目標狀態(tài)是復合狀態(tài),嵌套的狀態(tài)機就必須包括一個初始狀態(tài),在進入復合狀態(tài)之后并在發(fā)出它的進入操作(如果有)之后,控制權將被傳遞給該初始狀態(tài)。如果其目標狀態(tài)是嵌套狀態(tài),那么,在發(fā)出復合狀態(tài)的進入操作(如果有)并發(fā)出嵌套狀態(tài)的進入操作(如果有)后,控制權將被傳遞給該嵌套狀態(tài)。
從復合狀態(tài)出發(fā)的轉移可能會以復合狀態(tài)或子狀態(tài)作為它的源狀態(tài)。在這兩種情況下,控制權先離開嵌套狀態(tài)(并在可能的情況下發(fā)出它的退出操作),然后離開復合狀態(tài)(并在可能的情況下發(fā)出它的退出操作)。其源狀態(tài)為復合狀態(tài)的轉移基本上會中斷嵌套狀態(tài)機的活動。
歷史狀態(tài)
除非另有指定,當轉移進入復合狀態(tài)時,嵌套狀態(tài)機的操作將從初始狀態(tài)開始重新執(zhí)行(除非轉移直接以子狀態(tài)為目標)。歷史狀態(tài)使狀態(tài)機可以重新進入在它退出復合狀態(tài)之前的最后一個活動子狀態(tài)。圖 4 顯示了如何使用歷史狀態(tài)的示例。

常用的建模技術
狀態(tài)機最多地用于建立對象在其生命期內的行為模型。當對象具有依賴于狀態(tài)的行為時,尤其需要使用狀態(tài)機。可能具有狀態(tài)機的對象包括:類、子系統(tǒng)、用例、接口(以聲明實現(xiàn)該接口的對象必須滿足的狀態(tài))和協(xié)議(以聲明實現(xiàn)該協(xié)議的對象必須滿足的狀態(tài))。并非所有對象都需要有狀態(tài)機。如果對象的行為很簡單,只是存儲或檢索數(shù)據(jù),那么該對象的行為就與狀態(tài)無關,它的狀態(tài)機也沒有多少用處。
要建立對象生命期的模型,需要包括三個事項:指定對象可以響應的事件、指定對這些事件作出的響應以及指定過去行為對當前行為的影響。對象生命期的建模還涉及到確定對象有意義地響應事件的順序,即從創(chuàng)建對象時開始,繼續(xù)到該對象被破壞時為止。
要建立對象生命期的模型:
將狀態(tài)機的環(huán)境設置為類、用例或整個系統(tǒng)。
如果環(huán)境是類或用例,則要收集相鄰的類,其中包括父類或通過關聯(lián)關系或依賴關系可以接觸到的類。這些相鄰類是操作的候選目標,并且是可以包括在警戒條件中的候選目標。
如果環(huán)境是整個系統(tǒng),則要將重點集中到系統(tǒng)的一個行為上,然后考慮在該方面涉及到的對象的生命期。整個系統(tǒng)的生命期通常會大得無法成為有意義的重點。
確定對象的初始狀態(tài)和終止狀態(tài)。如果初始和終止狀態(tài)具有前提條件和后續(xù)條件,也應將這些條件定義出來。
確定對象要響應的事件。這些事件可以在對象的接口或協(xié)議中找到。
按照從初始狀態(tài)到終止狀態(tài)的順序,列出對象可能處于的頂層狀態(tài)。將這些狀態(tài)與相應事件所觸發(fā)的轉移連接起來。然后添加這些轉移。
確定所有進入操作或退出操作。
通過使用子狀態(tài)來擴展或簡化狀態(tài)機。
檢查狀態(tài)機中的所有事件觸發(fā)轉移是否與該對象實現(xiàn)的接口或協(xié)議所期望的事件相符。同樣,檢查對象的接口或協(xié)議所期望的所有事件是否都得到了狀態(tài)機的處理。最后,確定要在哪些地方明確地忽略事件(如延遲的事件)。
檢查狀態(tài)機中的所有操作是否都得到了包含對象的關系、方法和操作的支持。
跟蹤狀態(tài)機,將它與事件及其響應的預期序列進行比較。搜索無法達到的狀態(tài)以及狀態(tài)機無法繼續(xù)向前的狀態(tài)。
如果要重新布置或重新構建狀態(tài)機,需檢查并確保語義沒有發(fā)生變更。
提示與技巧
當給定一項選擇時,要使用狀態(tài)機的可視語義,而不要寫出詳細的轉移代碼。例如,不要用幾個信號觸發(fā)一個轉移,然后使用詳細代碼來管理以不同的方式依賴于信號的控制流。應使用由單獨的信號來觸發(fā)的單獨轉移。在隱藏了附加行為的轉移代碼中,要避免使用條件邏輯。
根據(jù)在狀態(tài)期間等待的事件或正在發(fā)生的事件來命名狀態(tài)。記住,狀態(tài)不是“時間點”;它是狀態(tài)機等待某個事件發(fā)生的時間段。例如,“waitingForEnd”這一名稱比“end”更好;“timingSomeActivity”比“timeout”更好。不要讓狀態(tài)的名稱看起來象是操作名。
在一個狀態(tài)機內唯一地命名所有狀態(tài)和轉移;這將便于進行源級別的調試。
謹慎使用狀態(tài)變量;不要在創(chuàng)建新狀態(tài)時使用它們。如果狀態(tài)不多,很少帶有或不帶有依賴于狀態(tài)的行為,并且很少有或根本沒有可能與包含狀態(tài)機的封裝體并行或獨立的行為,就可以使用狀態(tài)變量。如果有復雜的、依賴于狀態(tài)的潛在并行行為,或者如果必須處理的事件可能來自于包含狀態(tài)機的封裝體之外,則應考慮使用構件封裝體。
如果單個圖中的狀態(tài)超過 5 * 2 個,就應考慮使用子狀態(tài)。在這里可以應用我們的常識:在一個非常規(guī)則的模式中可以有十個狀態(tài),但如果兩個狀態(tài)之間具有四十個轉移,顯然就需要重新考慮了。務必要使狀態(tài)機易于理解。
使用觸發(fā)事件的事件和/或在轉移期間發(fā)生的事件為轉移命名。選擇更加易于理解的名稱。
當您看見一個選擇點時,應考慮是否可以將作出該選擇的職責委托給另一個構件,以便將其作為一組將不同的信號提供給封裝體遵照執(zhí)行(例如,代替對消息->數(shù)據(jù) > x 的選擇),并考慮是否可以讓發(fā)送方或另一中間主角來作出決定,然后通過在信號名稱中明確顯示該決定的方式發(fā)送信號(例如,使用名為 isFull 和 isEmpty 的信號,而不是以值命名信號并檢查消息數(shù)據(jù))。
為在選擇點中回答的問題指定描述性的名稱,例如“isThereStillLife”或“isItTimeToComplain”。
在任何給定的封裝體中,盡量使選擇點名稱保持唯一(其原因與轉移名稱需保持唯一相同)。
轉移的代碼段是否太長?是否應使用函數(shù)來代替它們,是否將常用代碼段記錄為函數(shù)?轉移應該類似于高層的偽代碼,并且應當遵循與 C++ 函數(shù)相同或更嚴格的長度規(guī)則。例如,代碼超過 25 行的轉移可被認為是過長。
應根據(jù)函數(shù)執(zhí)行的操作來命名函數(shù)。
要特別注意進入和退出操作:在進行更改后忘記更改相應進入和退出操作的情況尤其容易發(fā)生。
退出操作可用于提供安全性功能,例如,從“heaterOn”狀態(tài)中的退出操作將關閉加熱器,在這里,操作被用來強制執(zhí)行一個斷言語句。
通常,除非狀態(tài)機是抽象的并且將由包含元素的子類來進行改進,否則子狀態(tài)應包含兩個或更多個狀態(tài)。
應該用選擇點來代替操作或轉移中的條件邏輯。選擇點容易被看到,而代碼中的條件邏輯則是不可見的,很容易被忽略。
避免使用警戒條件。
如果事件觸發(fā)了幾個轉移,將無法控制首先對哪個警戒條件求值。這會產生無法預料的結果。
可能有多個警戒條件為“True”,但隨后只能有一個轉移。所選擇的路徑是無法預料的。
警戒條件是不可見的;要“看見”它們的出現(xiàn)更是困難。
避免使用類似流程圖的狀態(tài)機。
這可能表示您試圖對并不實際存在的抽象概念進行建模,例如:使用一個封裝體來對最適合于數(shù)據(jù)類的行為進行建模,或通過使用緊密耦合的數(shù)據(jù)類和封裝體類來對數(shù)據(jù)類建模(例如,數(shù)據(jù)類用于向四周傳遞類型信息,但封裝體類包含了應與數(shù)據(jù)類相關聯(lián)的大部分數(shù)據(jù))。
狀態(tài)機的這種錯誤用法可以通過以下故障現(xiàn)象來識別:
被發(fā)送給“自己”的消息,主要是為了重復使用代碼
幾乎沒有狀態(tài),但有很多選擇點
在某些情況下沒有循環(huán)的狀態(tài)機。在流程控制應用程序中,或者在試圖控制一個事件序列時,這樣的狀態(tài)機是有效的;如果它們在分析過程中出現(xiàn),則表示狀態(tài)機已退化為流程圖。
當發(fā)現(xiàn)問題時,應采取以下措施:
考慮將封裝體分解為職責更明確的小單元,將更多的行為轉移到與有問題的封裝體相關聯(lián)的數(shù)據(jù)類中。
將更多的行為轉移到封裝體類函數(shù)中。
制作更有意義的信號,以避免對數(shù)據(jù)的依賴。
使用抽象狀態(tài)機進行設計
抽象狀態(tài)機是需要添加更多細節(jié)才能實際使用的狀態(tài)機。抽象狀態(tài)機可用于定義可復用的一般行為,這些行為將在隨后的模型元素中得到進一步的改進。

請考慮圖 5 中的抽象狀態(tài)機。例如,圖 5 中的簡單狀態(tài)機代表了實時系統(tǒng)中許多不同元素類型的最抽象的行為(自動“控制”)。盡管不同的元素類型都具有這一最高抽象程度,但是,根據(jù)其目的,它們可能在“Running”狀態(tài)中具有非常不同的詳細行為。因此,該狀態(tài)機最有可能在某個抽象封裝體類中定義,該封裝體類被用作不同的專用封裝體類的根類。
因此,我們將使用繼承來定義該抽象狀態(tài)機的兩種不同的改進形式。圖 6 顯示了這兩種改進形式 R1 和 R2。為清晰起見,我們使用淺灰筆來描繪從父類繼承而來的元素。

這兩種改進形式的明顯差異在于它們分解“Running”(正在運行)狀態(tài)的方式,以及它們擴展原“start”(開始)轉移的方式。當然,只有當改進形式已知,因而未在抽象類中使用單個端到端轉移來實施時,才能作出這些選擇。
鏈式狀態(tài)
對于上述的改進類型而言,能夠同時“繼續(xù)”輸入轉移和輸出轉移是基本的能力。結合使用進入點、終止狀態(tài)和繼續(xù)轉移似乎就足以提供這些語義。但是,如果有多個不同的轉移需要擴展,這就行不通了。
在這種情況下,抽象行為模式需要的是用一種方法把在單個運行至結束的步驟中全部執(zhí)行的兩個或更多個轉移段鏈接起來。這意味著,要將進入分層結構狀態(tài)的轉移拆分成一個在狀態(tài)邊界處有效終止的進入部分,以及一個在狀態(tài)內繼續(xù)的擴展部分。同樣,將分層嵌套的狀態(tài)所發(fā)出的輸出轉移分為一個在包含狀態(tài)邊界處終止的部分,以及一個從狀態(tài)邊界繼續(xù)到目標狀態(tài)的部分。通過引入鏈式狀態(tài)的概念,可以在 UML 中獲得這一效果。它通過 UML 狀態(tài)概念的原型 (?chainState?) 來建模。該狀態(tài)的唯一目的是將更多的自動(無觸發(fā)器)轉移“鏈接”到輸入轉移上。鏈式狀態(tài)沒有內部結構:沒有進入操作,沒有內部活動,沒有退出操作。它也沒有由事件觸發(fā)的轉移。但它可以有任意數(shù)量的輸入轉移。鏈式狀態(tài)可能有不帶觸發(fā)事件的輸出轉移;當輸入轉移激活鏈式狀態(tài)時,該轉移將自動觸發(fā)。這種狀態(tài)的目的是將輸入轉移鏈接到獨立的輸出轉移上。在輸入轉移和被鏈接的輸出轉移之間,一個狀態(tài)連接到包含狀態(tài)內部的另一個狀態(tài),而該狀態(tài)又連接到包含狀態(tài)外部的另一個狀態(tài)。引入鏈式狀態(tài)的目的是將包含狀態(tài)的內部規(guī)約與其外部環(huán)境分隔開,這也是一種封裝。
實際上,鏈式狀態(tài)代表的是一種“串通”狀態(tài),它用于將某個轉移鏈接到一個特定的繼續(xù)轉移。如果沒有定義繼續(xù)轉移,轉移就會在鏈式狀態(tài)中終止。要使操作繼續(xù),就必須觸發(fā)包含狀態(tài)中的某一轉移。
圖 7 中的示例狀態(tài)機段顯示了鏈式狀態(tài)及其符號。鏈式狀態(tài)在狀態(tài)機圖中表示為在適當分層結構狀態(tài)內的白色小圓(該符號類似于與它們相似的初始狀態(tài)和終止狀態(tài))。圓是鏈式狀態(tài)原型的原型圖標,為了方便,通常把它們描繪在邊界附近。(實際上,另一種標志法是把它們描繪在包含狀態(tài)的邊界上,類似于封裝體上的端口符號。)

該示例中,被鏈接的轉移包括三個被鏈接的轉移段 (e1/a11-/a12-/a13)。當收到信號 e1 時,將調用標記為 e1/a11 的轉移,執(zhí)行它的操作 a11,然后進入鏈式狀態(tài) c1。接著,調用 c1 和 c2 之間的繼續(xù)轉移。最后,由于 c2 也是鏈式狀態(tài),所以從 c2 轉移到 S21。如果沿這些路徑的狀態(tài)都有退出和進入操作,那么實際的操作執(zhí)行順序將是:
S11 的退出操作
操作 a11
S1 的退出操作
操作 a12
S2 的進入操作
操作 a13
S21 的進入操作
以上所有操作都將在單個運行至結束的步驟中執(zhí)行。
應將這些操作與直接轉移 e2/a2 的操作執(zhí)行語義進行對比,后者是:
S11 的退出操作
S1 的退出操作
操作 a2
狀態(tài) S2 的進入操作
狀態(tài) S21 的進入操作 ? 1987 - 2001 Rational Software Corporation。版權所有。
通用準則
當行為的改變和狀態(tài)有關時才創(chuàng)建狀態(tài)圖。
敏捷建模( AM) ( Ambler 2002)的原則--最大化項目干系人的投資--建議你只有當模型能夠提供正面價值的時候才創(chuàng)建模型。如果一個實體,比如一個類或組件,表示的行為的順序和當前的狀態(tài)無關,那么畫一個UML狀態(tài)圖可能是沒有什么用處的。例如一個SurfaceAddrESs類就很簡單,表示了那些你將會在系統(tǒng)中顯示和操作的數(shù)據(jù),因此一個UML狀態(tài)圖就沒有任何相關之處。而一個Seminar對象就非常的復雜,學生注冊這樣一個事件將會根據(jù)它的當前狀態(tài)有不同的反應,就像你在圖1中看到的。

把初始狀態(tài)放置在左上角。
如你在圖1所見的,初始狀態(tài)被建模成一個實心圈,把初始狀態(tài)放在左上角反映西方人的閱讀文化的習慣。
把最終狀態(tài)放置在右下角。
如你在圖1所見,最終狀態(tài)被建模為一個帶邊界的實心圓。把最終狀態(tài)放右下角反映了西方的文化的從左到右,從上到下的閱讀習慣。
狀態(tài)指南
狀態(tài)是一個實體的行為模式的某個階段。 狀態(tài)的表示是通過實體的屬性值。 例如,在圖1中,當seminar被標記為open,并且存在空位的時候,seminar就處于Open For Enrollment的狀態(tài)。
狀態(tài)名稱要簡單但應具有描述性。
象Open For Enrollment和PropOSed這種的狀態(tài)名稱很容易理解,從而提高了圖⒈的溝通價值。理論上狀態(tài)名稱應該是現(xiàn)在時,但是用過去式寫成的諸如Proposed的名稱要比用現(xiàn)在時寫成的諸如Is Proposed的名稱好的多。
避免"黑洞"狀態(tài)。
黑洞狀態(tài)是那種只有變換進來但沒有任何變換發(fā)出的狀態(tài),這種情況要么由于該狀態(tài)是一個最終狀態(tài),要么就是你已經錯過了一個或多個變換變換。
避免"奇跡"狀態(tài)。
奇跡狀態(tài)是那種只有變換發(fā)出但沒有任何變換進來的狀態(tài),這種情況要么由于該狀態(tài)是一個起點,要么就是你已經錯過了一個或多個變換變換。
子狀態(tài)建模指南
為復雜的目標建模子狀態(tài)。
圖1中展示的UML狀態(tài)圖是不完整的,因為它沒有建模Seminar的poST - enrollment(注冊后)狀態(tài)。 圖2建模了一個Seminar的完整的生命周期,把圖1描述為一個新的包括子狀態(tài)集合的Enrollment的復合狀態(tài),也稱作超狀態(tài)。注意按理說你會像圖1的模型那樣處理標記,但為了簡化起見在原先變換上的標記都沒有包括在內。當一個現(xiàn)有狀態(tài)表現(xiàn)出復雜的行為時,建模子狀態(tài)就是有意義的,從而促使你來研究它的子狀態(tài)。當幾個現(xiàn)有狀態(tài)共用一個通用的入口條件或出口條件( DouglASs 1999)時,引入超狀態(tài)是有意義的,在圖1中你可以看到所有的狀態(tài)共用一個通用的closed變換,以到達最終狀態(tài)。

把通用的子狀態(tài)變換放在一起
和圖1中每一個子狀態(tài)都擁有一個cancelled變換不同,在圖2中你可以看到cancelled變換僅用于描述Enrollment超狀態(tài),這使圖形得到簡化。如果子狀態(tài)都共享一個入口變換或出口變換,都可以使用一個同樣的方法。 變換上的警戒點和動作(如果有)也應該使相等的。
為復雜的實體創(chuàng)建一個分層的狀態(tài)圖
雖然這種表現(xiàn)子狀態(tài)的方法是很好使的,但是最終的圖可能變得相當復雜--我們只要設想一下如果Being Taught狀態(tài)也有子狀態(tài)的話,圖2會變成什么樣就知道了。 一個替代的方法是創(chuàng)建一個分層的UML狀態(tài)圖。 例如,圖3表示高階視圖,而圖1描述了一個細節(jié)視圖。這種方法的好處是如果需要的話,馬上就可以建立一張詳圖來研究Being Taught狀態(tài)。

最高階的狀態(tài)圖總有初始態(tài)和最終態(tài)
一個高階的UML狀態(tài)圖,例如圖2描述的這樣,應該表示實體的完整的生命周期,包括"出生"和最后的"死亡"。 低階的圖未必包含初始狀態(tài)和最終狀態(tài),特別是那些建模一個實體的生命周期的"中間狀態(tài)"的圖。
變換和動作
變換是從一種狀態(tài)到另一種狀態(tài)的序列,它可能是通過一個事件觸發(fā)的。簡而言之就是被建模的實體的內部或外部的行為。 對一個類來說,變換一般是將會導致狀態(tài)的重要改變的操作調用的結果,因此我們需要了解一點,并不是所有的方法調用都會導致變換產生的,這一點非常重要。一個動作就是某個東西,對類來說就是一個操作,被建模的實體所調用的操作。
用實現(xiàn)語言的命名規(guī)則命名軟件動作
圖1中的動作遵循Java操作的命名規(guī)則( Vermeulen et. 2000),因為系統(tǒng)使用
用敘述性文字命名角色動作
UML狀態(tài)圖可用于建模非軟件實體的生命周期,特別是UML圖上的角色。 例如學生角色就可能有諸如Accepted、Full Time、Part Time、Graduated、Masters、Doctoral、和Post - Doctoral等狀態(tài),以顯示各人的不同行為。 當你在建模現(xiàn)實世界的角色時,與軟件中Student類不同的是,狀態(tài)間的變換最好是使用敘述性文字來描述,例如drop seminar和pay fees,而不是dropSeminar ()和payFees (),因為現(xiàn)實生活中的人是做事情,而不是執(zhí)行操作。
只有對所有的入口變換都合適時才注明入口動作
在圖1中你可以看到Closed To Enrollment狀態(tài)的入口中操作notifyInstructor ()都是經由entry/動作標記來調用的。 這暗示著每次進入狀態(tài)時都需要調用該操作,如果你不希望每次都發(fā)生,那么就把動作關聯(lián)到特定的入口變換。例如,addStudent ()動作是在student enrolled變換到Open For Enrollment變換發(fā)生,而在到opened變換則不會發(fā)生,這是因為每次你在進入該狀態(tài)并不需要增加一個學生。
只有對所有的出口變換適合時才注明出口動作
出口動作,用exit/標記來表示,工作方式類似于入口動作。
只有當你想終止并再進入該狀態(tài)時才建模遞歸變換
一個遞歸的變換是那些兩個端點都擁有相同狀態(tài)的變換。 一個重要的暗示是實體從狀態(tài)出來,又回到原有的狀態(tài),因此,那些由于entry/或exit/動作標記而被調用的任何一種操作都可能被自動調用。 圖1的Open For Enrollment狀態(tài)就是這種遞歸變換的例子,因此當前班級大小就在入口處被記錄下來。
用過去式命名轉換事件
圖1中的轉換事件,例如seminar split和cancelled,是使用過去式命名的,反映了這樣一個事實:變換是事件的結果--因為事件發(fā)生在變換之前,因此應該用過去式命名。
把轉換標記放在接近源狀態(tài)的地方
雖然圖1比較復雜,變換標記盡可能放在靠近來源的地方,例如seminar split和student enrolled。 Furthermore, the labels were justified (left and right respECtively) to help visually place them close to the source state.
以轉換方向為基礎放置變換標記
為了更易于判斷哪個標記和變換是一起的,按照如下的規(guī)則來放置變換標記:
在變換線條上的從左到右。
在變換線條下的從右到左。
變換線條右邊的往下。
變換線條左邊的往上。
警戒點
一個警戒點是為了穿過一個轉換而必須為真的一個條件。
警戒點不應該重疊
離開狀態(tài)的相似變換上的警戒點必須彼此一致。 舉例來說,x <0, x = 0,以及x > 0的警戒點是一致的,而x < = 0和x > = 0的警戒點就不是一致的,因為他們重疊了,它并沒有明確的指出當x為0時將發(fā)生什么。在圖1中,你可以看到警界點的一致性,從填寫注冊表活動出發(fā)的該學生劃線變換上的警戒點沒有重疊,決策點上的警戒點也一樣。
為可視化的定位警戒點而引入接合點。
在圖2中你可以看到從Being Taught觸發(fā)student dropped事件存在兩個變換,而圖3中僅有一個,變換被合并了,因此我們需要一個接合點(填滿的圓)。 這種方法的好處是現(xiàn)在圖上的兩個警戒點更彼此接近了,更容易看出警戒點是否重疊。
警戒點不必配套
一個狀態(tài)的變換警戒點有可能是不完整的。例如,一個bank account對象可能從Open狀態(tài)變換到Needs Authorization狀態(tài),這時需要一個大額存款"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之類的描述就是不一致,而且難于理解的。