打開獲取需求的大門——用例圖繪製指南
1.前言
1.1.簡介
使用UML繪製用例圖是表現系統需求的一種方式,是分析獲取需求的一種有效手段。用例圖是了解系統的第一個關口,通過用例圖可以知道系統有哪些角色,這角色通過系統能做什麼事情。在用例圖中,會體現與系統交互的參與者、功能模組,以及系統工作的基本流程等。站在客戶的角度上看,用例圖是他們業務領域的邏輯化表達方式;站在軟體供應商的角度上看,用例圖是系統藍圖和開發的依據,這說明用例圖在軟體製作的期間很好的起到了承上啟下的作用。儘管它通常不會展現細節方面,但它是一個可以用於溝通複雜想法的好方式。
1.2.主要元素
1.3.元素符號
1.4.目的
本篇希望作為一篇面向實用性的指南,其目的是為了能夠幫助初學者,快速掌握用例圖的基礎知識和繪製方法,以便於用於實踐中,在實踐中不斷的感悟。另外的一個目的則是作為查閱手冊,如果在實際的工作中遇到了比較模糊的地方,可以通過本篇文章快速查閱回顧知識點,以便解決實際的問題。接下來,本篇將根據用例圖的主要元素逐一展開講解,講解每個元素時,會採用理論和示例並行的講解方式,以便於在每個元素的使用場景上,能夠加深對元素概念的理解。
2.系統邊界
2.1.概述
在UML的用例圖中,我們通常將系統邊界視作我們構建的軟體系統,它可以是網站、軟體組件、業務流程、App等應用程式,亦或是你要開發的任何東西。系統邊界作為用例圖中的元素可以用一個矩形來表示,其名稱位於矩形內的頂部。系統邊界使用矩形元素,實際上僅僅是一個表現形式,它在有些應用場景中甚至是無形的。從概念上來說它屬於一種分析方法,通過邊界可以決定看待系統的抽象層次和視角,進而排除邊界外大量的雜音來降低複雜程度,從而界定系統的範圍,知道系統能幹什麼,系統不能幹什麼。
確定一個邊界,就好比如你決定採用什麼方式來介紹一個事物一樣。人體的器官大約有315個,如果不設定邊界,那麼你介紹器官的時候就會毫無條理、天馬行空。介紹內臟器官(心、肝)的時候一下就跳到介紹外部器官(耳、鼻),到最後聽你介紹的人根本搞不清楚你講的重點。因此,我們需要通過設定邊界,將我們所講的事物確定在同一個領域範圍,並且事物的粒度要保持相同體量。還是回到人體器官上來,如果設定的邊界是內臟器官,此時我們的視角必然在身體內部,抽象出來的事物都屬於該邊界內同粒度的器官(心、肝、肺等);如果設定的邊界是外部器官,那麼我們的視角必然在身體外部,抽象出來的事物都屬於該邊界內同粒度的器官(眼、耳、鼻、嘴等);
沒有邊界的地方將會是混沌的,例如你去一所學校去找人,如果學校沒有設定邊界,那麼你找人就像是「大海撈針」,因為所有人都交織在一起。如果學校根據不同領域設定邊界,那麼學校內部就會規劃為:教室、辦公室、圖書館等等區域。那麼此時你找人就不會在茫茫人海中尋找,而是可以針對性有範圍的找,比如找學生可以去教室,找老師可以去辦公室。一個全新的軟體項目對我們來說,也是混沌的,需要我們設定邊界,才能從混沌走向清晰。
總的來說,通過邊界的劃分會影響到我們觀察的事物,從而就決定了抽象層次和視角,使得我們分析事物的粒度可以保持統一,並且讓系統的作用範圍更加清晰。邊界和面向對象同樣都屬於軟體設計領域中的內功,我們並能奢望一朝一夕就將其掌握,我們先做到一個初步的認識,然後在日後的實踐中不斷去感悟和學習。
2.2.示例背景
本文用於講解用例圖使用的應用場景,是來自日常通勤的共享單車。本文將使用共享單車的軟體系統作為示例,以此來展開用例圖的繪製,我會根據用例圖中元素的使用特點,選擇其中常用的功能(掃碼用車、鎖車、付款、退押金)作為素材。在繪製之前,希望大家腦補一下你使用共享單車通勤的場景,這有助於理解其中的業務需求,以便我們有針對性的繪製相應的用例圖。由於這是根據現實生活中已經存在的應用,來反向推導出與之對應的用例圖的情況,所以我們可以直接將共享單車的軟體視為系統邊界,並將其命名為「共享單車騎行系統」。
3.參與者
3.1.概述
參與者在UML用例圖中是由一個「火柴人」來表示。UML官方對其的定義是:「參與者是在系統之外與系統交互的某人或某事物」。參與者不是系統的組成部分,所以它處於系統的外部。參與者通常是一個使用系統的人,但有時也可以是一個外部系統或外部因素、時間等外部事物。參與者對系統有著明確的目標/願望,並且希望通過與系統交互所產生的結果,可以它的實現目標/願望。由於參與者必須與系統進行交互,因此可以從這個角度去分析獲取那些候選的參與者。
具體來說,識別參與者可以參考以下幾個思路:
- 系統會被哪些部門使用。這些使用系統的部門用戶,可以根據共同的職責提煉出一個參與者。
- 誰向系統提供資訊、使用或刪除資訊。對系統資訊進行管理的人員也會作為參與者與系統交互。
- 誰與系統的需求有關聯。因關聯被動參與到需求的事物,也可能會作為參與者使用到系統中的相關功能。
- 誰對系統進行維護。日常的維護業務也需要參與者與系統進行交互來完成。
- 與外部系統是否有交互。這些外部系統往往會成為參與者。
- 時間參與者,如一些具備定時功能的組件,它會激活哪些系統定期的、自動執行的業務。
在參與者當中還會分為主要和次要的參與者,主要參與者是主動發起了對系統的使用,通常繪製在邊界的左側;次要參與者與系統的交互是被動的,通常繪製在邊界的右側。例如對於某公司的工資管理系統,公司財務負責人會主動發起工資的發放操作,但實際的資金轉移需要銀行來介入完成,這其中財務負責人就是主要參與者,而銀行由於工資的發放從而介入系統的交互,所以銀行屬於次要參與者。
參與者代表的是特定類型,而不是代表的具體的人或物,參與者相當於根據人或物共同職責提煉出的某類角色。所以在為參與者命名時需要注意,不要定義為某個具體的人或物(張三、發財銀行),而是應當定義具有代表性的名稱(客戶、銀行)。
3.2.示例
當我們去分析一個系統時,不應直接從系統本身具備的功能開始思考,我們應當先思考系統會為誰提供哪些價值,有哪些參與者會與這個系統進行交互來實現目標,因為系統的價值就體現在為參與者實現目標上。對於本示例的「共享單車騎行系統」而言,它可以提供單車的使用為人們帶來交通的便利。作為使用者,他能夠通過系統得到單車的使用。在這個分析中,很明顯,騎行者是對該系統有著明確目標的人,並且他屬於系統外部。所以可以將騎行者定義為「共享單車騎行系統」的參與者。
為了引出主要和次要參與者的使用場景,我們來思考下退押金這個業務。共享單車公司通過繳納押金的手段保證單車在一定程度的安全,作為騎行者而言,在沒有單車使用需求的情況下,可以要求公司退押金。由於「共享單車騎行系統」中沒有包含公司的資金業務,所以該系統想要實現騎行者退押金的目標,必須依靠公司另外的財務系統。當騎行者發起退押金的操作時,「共享單車騎行系統」會向外部的財務系統發送申請,押金最終會由財務系統打到騎行者的銀行卡上。
對於這個退押金業務場景而言,騎行者是主動發起對系統的使用,而財務系統與系統的交互是被動的。只有騎行者做了一些事之後,財務系統才會參與到系統中來採取相應行動。綜上所述,該業務其中的主要參與者是騎行者,次要參與者是財務系統。下面將這兩個參與者補充到本示例的用例圖中。
4.用例
4.1.概述
在系統的角度上看,用例是它對外向參與者提供的價值。在參與者的角度上看,用例是參與者對系統寄予的目標。參與者通過系統內部提供的用例與之交互,從而根據交互產生的結果達到參與者的目標。分析用例的主要作用是捕捉功能性需求,一個系統的功能性需求就是由參與者對系統各種各樣的目標構成的,當全部參與者的所有目標,都能夠通過系統提供的用例來達到時,那麼這個系統就被確定下來了。用例的提出和定義都是從參與者的角度來考慮的,通過分析參與者使用系統實現的目標來獲取相應的用例。
具體來說,識別用例的思路可以參考以下幾點:
- 參與者的日常工作處理的業務流程有哪些?可以從這些流程中概況出用例(流程處理什麼事)。
- 參與者在業務中承擔哪些職責、起到什麼作用?業務中承擔的職責或起到的作用可能存在用例。
- 參與者是否會生成、使用或刪除與系統相關的資訊?系統需要提供相應的用例給參與者進行管理和維護。
- 參與者是否需要把外部變更通知給系統?通常系統的過程也需要用例支援。
- 系統是否需要把內部事情通知給參與者?通知參與者的過程就是系統用例的行為。
- 是否存在進行系統維護的用例?相關的維護用例也會在系統中存在。
確定了用例後就需要定義用例的名稱,通常用例的名稱的結果應該是:<狀語>動詞+<形容詞>賓語。其中狀語和形容詞可以根據情況修飾,而動賓則是必須的主體結構。名稱的結構也可以作為衡量用例準確性的標準,通常參與者和用例名稱在一起是「主謂賓」的結構,例如會員訂購商品。
在分析用例是還需要注意粒度的問題,應當避免出現以下幾種過分細化的情況:
- 不要把完成一個用例需要的步驟當成單個用例;
- 不要把實現用例的手段分解成多個用例;
- 不建議把常規維護性操作(增刪改查)拆分成單個用例;
4.2.示例
在基本概述用例之後,接下來我們將針對本示例「共享單車騎行系統」的應用場景,分析並獲取其中的用例。有效識別用例最基本的就是站在參與者的角度來考慮,你可以思考下你作為騎行者對一款「共享單車騎行系統」會有哪些期望或目標。
根據日常的使用場景並結合作為示例的素材考慮,騎行者比較普遍的目標一般包含:掃碼用車、鎖車、付款、退押金。另外需要強調的是,系統能夠為參與者實現目標是系統的基本原則,參與者的目標也不能天馬行空,參與者的目標應當是系統力所能及的,在系統邊界內的。接下來,我們將以上提到的騎行者的目標作為用例,並將其補充到當前示例的用例圖中。用例對應的符合是橢圓形,並且用例需要包含在系統邊界的矩形之中。
5.關係
5.1.關聯
在識別並繪製參與者和用例之後,在圖中它們還處於相互獨立的狀態,實際上參與者和用例之間還存在著某種關係,稱之為關聯。這裡的關聯和類之間的關聯有所不同,它表示參與者和用例之間存在資訊交互,象徵兩者之間有基本的交流或者互動。關聯採用一條「實線」表示,這條線可以在指向用例的方向帶上箭頭,也可以不帶箭頭。這個箭頭並不代表數據流或業務流的方向,因為參與者和用例之間是雙向交互資訊的,所以這裡的箭頭表示由通訊的主動方(參與者)啟動被動方(用例)。為了避免箭頭帶來的邏輯混淆,建議不帶箭頭。
接下來,我們將針對「共享單車騎行系統」用例圖中的參與者和用例,通過繪製實線建立關聯關係。在繪製中請注意,在本文講解參與者的段落中,關於退押金的業務場景,我們分析出了主要和次要的參與者。所以對於這個情況,次要的參與者(財務系統)也需要和參與的用例(退押金)建立關聯關係。
請記住,所有的參與者,都必須至少與一個用例產生關聯並與之交互,不存在沒有參與者的用例,也不存在沒有用例的參與者,否則請檢查用例和參與者的分析結果。下面將本示例中參與者和用例之間的關聯關係,將其補充到用例圖中。
5.2.包含
簡介:
包含關係提供了從多個用例中提取公共部分的能力,把公共部分作為單獨的用例,系統可以通過包含關係對其進行引用。因此,包含關係的提出一般是基於用例行為復用的考慮,這意味著被包含的用例往往被多個基本用例引用。對其的使用標準總結為:如果在兩個或更多的基本用例中存在類似的行為,並且這些類似的行為又可獨立地構成一個用例,那麼就可以把這些行為提煉出來構成一個被包含的用例。包含用例與衍生它的多個基本用例之間就屬於包含關係,包含關係在用例圖中的表示:使用一條帶箭頭的虛線,並在虛線附近加上<<include>>,箭頭的方向由基本用例指向包含用例。
基用例和包含用例:
包含用例的執行並不是由參與者直接發起的,而是由基礎用例執行時觸發的,基本用例一旦執行,對應的包含用例就必須會執行。另外,基本用例想要完整的執行,就必須執行它所包含的用例。從這點可以看出,包含用例對基本用例而言相當於一種「必須品」,沒有包含用例,基本用例是不完整的。而對於包含用例而言,如果沒有基本用例,包含用例是不能單獨存在的。兩者的關係就像是「有你才有我」一樣。
示例:
讓我們回到「共享單車騎行系統」中來思考其中是否存在包含關係。基於包含關係是對行為復用的考量,我發現可以在付款和退押金這個兩個用例中,找到公共的部分,並且屬於必須執行的行為。 付款時,系統必須會檢查你上一次的付款情況,避免過度透支使用;退押金時,系統也會檢查你的付款情況,避免出現錯誤的免單情況;因此,這兩個用例中就可以抽取公共行為「檢查未付款」,而這個公共行為即可構成一個單獨的被包含用例。下面將用例補充到當前示例的用例圖中,並建立包含關係。
5.3.擴展
簡介
擴展表示的意思是:在基本用例的基礎上,思考基本用例在處理自身行為之外,還能做什麼有易於業務需求的事情,如果存在,那麼就把這個事情委託給其他用例(擴展用例),表示該事情被擴展了,以此在基本用例和擴展用例之間就形成了擴展關係。在擴展關係中,基本用例自身是獨立完整的,不受擴展用例影響,不需要擴展用例也能夠向參與者提供價值。但是擴展用例的存在將由基本用例決定。擴展關係在用例圖中,是用一條帶箭頭的虛線並在線上加<<extend>>來表示的,箭頭方向指向基本用例,表示擴展用例是根據基本用例進行擴展的。
擴展點
為了表面擴展用例在基本用例中是基於什麼情況擴展的,需要在基本用例中定義擴展點,擴展用例只能在它與之對應的擴展點上進行擴展。擴展點是指在基本用例中定義的特定條件,每個擴展用例都至少與一個擴展點相關聯。當基本用例滿足擴展點的特定條件後,就會觸發相應的擴展用例的執行,從而為基本用例提供附加行為。需要注意,有些工具可能在繪圖上並不會將擴展點顯示出來,但無論顯示與否,只要存在擴展關係,基本用例中就存在與之對應的擴展點。
示例
我們將擴展關係的特點投射到本示例的「共享單車騎行系統」中來,思考分析下哪些用例可以進行擴展。我個人作為共享單車的常用者,我覺得每當騎行到達目的地離開單車後,總是會擔心自己因為沒有將單車鎖上,導致無限扣費的情況。我覺得要是在鎖車後要是能夠向我發送一條確認資訊,我將會安心許多。基於這個痛點,實際上我們可以在鎖車的用例上進行擴展,擴展一個在鎖車後向騎行者發送鎖車消息的用例,並且發送鎖車消息的擴展用例還不會影響到鎖車,僅作為一個輔助性質。下面我們將這個擴展用例補充到示例的用例圖中看看效果吧。
5.4.包含和擴展的對比
包含關係和擴展關係是在用例建模中比較常用的關係,也是初學者容易混淆的兩種關係。從表面上來看,它們都是使用虛線箭頭作為表達關係的符合,只是箭頭方向和虛線上的標識不同而已。所以,如果我們想要清晰、正確的使用這兩種關係,就必須通過對比分析,來理解這兩種關係的使用場合和所解決的問題。下面通過表格對這兩種關係進行了詳細的對比,在實際應用中可以進行參考,並結合具體情況選擇合適的關係。
5.5.用例的泛化
簡介
泛化關係相當於面向對象三大特徵之一的繼承,該關係可以用於在用例之間或參與者之間。用例和參與者之間的泛化都表面了一種繼承層次,通過繼承層次,繼承派生出的子項可以獲得上層項中全部屬性和行為,並參與上層項中的各種關係。因此,通過泛化關係可以在用例圖中達到更大範圍、高層次的需求復用。
在用例之間的泛化關係當中,父類稱為泛化用例,子類被稱為特化用例。泛化用例中描述通用行為,而在特化用例中繼承這些通用行為,並在適當地方進行特化。在實際中,泛化用例往往作為抽象用例,這代表它不會產生任何具體的場景實例,僅作為抽象標準(類似介面),參與者只會通過執行特化用例來實現目標。
在實際中,包含關係在用例之間的關係中應用的最多,再者是繼承關係,而泛化關係用的最少。因為對於客戶而言,由於它們往往缺少面向對象的知識,所以難以理解其中的概念。如果僅僅為了將用例之間的可復用部分或用例的可擴展部分描述出來,那麼使用包含關係和擴展關係就足夠了,使用用例的泛化很可能增加用例圖的理解成本。
示例
在本示例「共享單車騎行系統」中,我們可以發現付款用例實際上是很寬泛的,因為付款的方式有很多,可以是:賬戶餘額、支付寶、微信、花唄等等方式。所以付款用例代表了一般情況,我們可以將其作為抽象用例,從它身上特化出具體的付款用例。泛化關係是用一條帶空心箭頭的直線表示的,箭頭的方向由特化用例執行泛化用例。下面我們將這個用例的泛化補充到當前實例的用例圖中。
5.6.參與者的泛化
在上文介紹用例泛化的基礎上,在來介紹下參與者之間的泛化是如何運用的。與用例的泛化一樣,參與者之間的泛化也是屬於一種繼承層次,同樣是滿足於更高層次的需求復用,只不過參與者的泛化在實際中使用的更多些。
我們針對本示例的「共享單車騎行系統」,思考這樣一個情況:如果系統要在普通用戶的基礎上推出一個VIP用戶,並且VIP用戶具備普通用戶所有的行為能力,那麼在繪圖時,VIP用戶是不是要將普通用戶的用例和關係都重複畫一遍呢?如果是,那麼後面如果有N個高層級用戶加入,是不是都需要將普通用戶所有的用例都要重複畫一遍呢?顯然這種重複性會讓用例圖的重複度和複雜度會大大提示,從而不堪入目。
對於上面的情況,就屬於我們在參與者中使用泛化關係的場景。通過建立普通用戶和VIP用戶之間的泛化關係,VIP用戶將基礎普通用戶的所有行為,所以在將VIP用戶作為參與者繪製到圖中時,就無需重複的繪製他和普通用戶之間存在的共同用例和關係。
在實際的應用中,我們也應當對所有參與者進行共同性的分析,共同性體現為,多個參與者存在相同的用例。如果存在共同性,我們應當抽象出一個「父類」參與者,其參與者都直接或間接基礎這個「父類」參與者。參與者之間的泛化關係也是使用帶空心箭頭的直線表示的,下面我們將VIP用戶和它特有的用例補充到圖中。
6.實踐建議
- 在客戶能準確全面的基礎上,用例越精簡越好。
- 用例應使用客戶的語言,需保證客戶能看懂,而不應參與技術性的描述。
- 在表達用例時要注意輕重之分,對於重點難點用例可通過注釋加以詳述,對於「常識」的用例則可簡言。
- 用例的粒度應當在同一個系統邊界中保持相同的體量。
- 不應盲目地從客戶無邊界的想法中直接獲取用例,用例更多地是從客戶對系統的目標中推導,且在系統邊界之內。
- 用例圖只是一種表現形式,掌握用例圖所承載的需求分析方法才是關鍵。
7.結語
繪製用例圖其實是件很容易的事情,只要你知道每個元素代表的符合,就能照葫蘆畫瓢的繪製出來。但是難點在於其中每個元素都蘊藏著很多複雜的概念,如識別參與者、分析系統邊界、分析用例、定義關係等,這些往往是需要經過一定的系統學習和掌握其中的概念才能做好的事情。所以比起繪製方式而言,更重要的是分析能力和實踐運用能力。
用例圖的構建,對於獲取需求而言,是非常有效的手段。而清晰明確的需求對於一個軟體項目的重要性,毋庸置疑。所以學會用例圖將會是你在獲取需求道路上披荊斬棘的利器。