萬字多圖 - UML 入門指南

1. 前言

談到面向對象技術的分析和設計,自然就離不開 UML。對於 UML 這個概念,很多程序員朋友耳熟能詳,也有在用,但在工作中,一些朋友其實並不擅長使用 UML 甚至對 UML 這個東西模棱兩可,也包括我自己。因此我希望可以結合自己的經驗和實踐,寫一篇 UML 的入門文章,幫助做面向對象的程序員朋友能更好的利用它,從而順利完成自己的編程設計工作。

2. 從一個示例開始

先舉個現實世界的例子。我們上大學的時候,作爲學生,每人都有一張學生證,會歸屬到一個班級,上學時可能會用到自行車。很多同學還會考駕照,挑放假時間練車,車可能是轎車也可能是皮卡。

如果想通過在線的方式記錄以上的信息和行爲,在軟件世界中如何表達呢?

相信很多朋友的操作是,找到這段話裏的主語和賓語,也就找到了這個例子中涉及的角色,然後通過動詞來判斷各個角色之間的關係和能力,最後用代碼的方式來表達,產出可執行的程序。

像下圖這樣,識別出關鍵的實體和它們之間的關係。

用軟件工程的方式,解決現實中的問題,是信息時代最明顯的特點,這讓我們的生活和工作變得更加便利。

但現實世界錯綜複雜,靈活多變,每個人的理解可能會有不同,從現實世界到軟件世界的映射,就變得困難重重,一團亂麻。

如何讓現實世界到軟件世界映射變的簡單容易,這就是 UML 要解決的問題。

3. 什麼是 UML

UML 全稱是 Unified Modeling Language(統一建模語言),它以圖形的方式來描述軟件的概念。

3.1 爲什麼稱 UML 爲語言

先說語言,爲什麼 UML 被稱爲語言?

名稱的落腳點是語言。既然是語言,那麼它就會具備語言的特性,比如結構上它由詞彙和語法構成,功能上它能解決溝通問題。

你熟知的語言裏比較多的應該是漢語和英語,如果從事軟件行業,C 語言和 Java 語言你應該也不會陌生。英語和 Java 語言明顯都是語言,卻常常不被放在一起討論,爲什麼?因爲它們是不同維度的語言。英語是解決現實世界中人與人之間溝通問題的人類語言,Java 是解決軟件世界中程序員與計算機之間溝通問題的計算機語言。

人類語言本質上是事實和觀點的表達,計算機語言本質上是 0 和 1 的表達。前者的表達形式是難以確定的,而且可能會產生歧義,所以纔會有「被誤解是表達者的宿命」這樣的觀點, 但後者就是確定性無歧義的 0 1 表達。

這麼看來,UML 的目標是通過一定結構的表達,來解決現實世界到軟件世界的溝通問題。

3.2 什麼是建模

再說建模,模是什麼,需要怎麼建?

建模簡單講,是指通過抽象的方式解決某個領域的問題。各個抽象角度共同組成了一個問題領域。

對於傳統模型而言,建造它是爲了證明這個問題領域下某件事物能否工作。當然它有前提,即建造模型的成本遠遠低於建造實物的成本。比如造飛機或造高樓。

對於軟件模型而言,建造它是爲了與他人溝通,也爲了保存這個問題領域下軟件設計的最終成果。當然它也有前提,就是模型比代碼更說明問題。

比如購物這個問題,甲可以在淘寶上買衣服,乙可以在亞馬遜上買書,丙可以在京東上買手機。

誰買東西?是甲、乙和丙,他們都能抽象成人。

買什麼東西?有衣服、書和手機,它們都能抽象成貨。

在哪裏買?在淘寶,亞馬遜和京東,它們都能抽象成場。

整體抽象一下就是人到場裏買貨。所以購物這個場景所抽象出來的人貨場,就用來解決零售領域的問題。當然還可能會有些規則,比如成爲註冊會員才能發生交易。

我們會發現,一個特定的事件(比如購物)裏,會有特定的人的行爲(比如甲乙丙要上電商網站),會有特定的物(比如貨),有特定的規則(比如註冊會員),共同完成購物這件事。

特定的事 = 特定的人的行爲 + 特定的物 + 特定的規則

在人貨場這個抽象角度裏,就會涉及到很多特定的事,包括會員註冊,會員下單,會員支付,商家發貨,快遞公司郵寄等等。

模簡單講,就是人、事、物和規則。

人是一切的中心,人要做事,做事就會使用一些物併產生另一些物,同時做事需要遵循一定的規則。

人驅動系統,事體現過程,物記錄結果,規則是控制。

建立模型的關鍵就是弄明白有什麼人,什麼人做什麼事,什麼事產生什麼物,中間有什麼規則,再把人、事、物之間的關係定義出來,一個模型也就基本成型了。

3.3 統一的意義在哪裏

統一的普遍意義是形成標準。所謂標準,就是所有人都明白的表述,所有人都遵從的格式。標準可以讓信息在人羣中無障礙地流通,即使這些信息來自不同地域、不同文化、不同社會或不同組織。

比如美元作爲國際統一使用的貨幣方便了全球的經濟貿易,我們國家普及普通話方便了不同地區的交流溝通。

在軟件世界,任何一種組件化開發模式背後都有一個標準在規範和指導,比如 Java 的 JSR 標準。有了標準,編程就容易組件化,協作效率也會提升很多。對 UML 來說,這就是統一的意義。

4. 爲什麼需要 UML

一個軟件項目要經歷業務調研、立項、需求採集、架構設計、編碼開發和測試驗證等多個環節。

每個環節可能角色並不相同,同樣的文檔同樣的話語越向後傳遞就越容易失真。因此就容易出現最終交付的產品不是客戶真正想要的這種情況。

如何避免角色間信息傳遞的失真,保證信息能被準確的傳達和準確的理解?一種好的辦法就是大家使用標準化的語言。

統一建模語言 (UML) 就試圖用標準化的語言來覆蓋整個軟件過程,讓不同團隊不同角色可以用相同的語言順暢的溝通。

在信息傳播方面,圖形相對於文字,人腦的接受能力顯然更強。因此,UML 採用了「可視化」的圖形方式來定義語言。

5. UML 的適用場景

UML 既可以描述某個問題領域,也可以表達構思中的軟件設計,還可以描述已經完成的軟件實現。

它適用於面向對象分析設計的整個過程。這個過程可以分爲三個階段,如下圖。

第一個階段是通過建模將現實世界轉爲業務模型。業務模型真實映射了參與者(業務活動的驅動者)在現實世界的行爲。

從圖裏可以看到,現實世界映射到業務模型後,是使用 參與者 和 用例 這兩個 UML 的核心元素表達的。參與者作爲一個特定事件的驅動者,用例則描述了這個驅動者的業務目標。文章後邊也會提到這兩個元素。

第二個階段是對業務模型概念化,建立適合計算機理解和實現的模型,也就是概念模型,或者叫分析模型。分析模型向上映射了原始需求,向下爲計算機實現規定了一種高層次的抽象,是一種過渡模型。

現實世界千差萬別的業務,都用 邊界、控制和實體這幾個核心元素來描述,同時也引入了 包、組件 這些與現實世界毫不相干的概念做包裝。

第三個階段是對概念模型實例化,得到相對詳細的設計模型。

在設計模型中,概念模型中的邊界類可以被轉化爲操作界面或者系統接口;控制類可以被轉化爲計算程序或控制程序,例如工作流、算法體等;實體類可以轉化爲數據庫表、XML 文檔或者其他帶有持久化特徵的類。

同樣的概念模型會因爲選擇不同而得到不同的設計模型。比如技術選型上使用不同的編程語言,不同的中間件就會得到不同的設計。

爲什麼需要這一道轉換呢

因爲 “邊界”、“控制”、“實體” 這些對象化的概念,雖然是計算機可以理解的,但它並不是真正的對象實例,也就是說它們並不是可執行代碼,概念模型只是紙上談兵。真正的對象世界行爲是由 Java 類、C++ 類、JSP 等這些可執行代碼構成的。

換句話說,設計模型是概念模型在特定環境和條件下的實例化,實例化後的對象行爲執行了概念模型描述的那些信息。

以下是面向對象分析設計的完整過程,它表達了現實世界是怎麼通過 UML 映射到對象世界的。

6. UML 的組成結構

前面花了比較大的篇幅分析了 UML 的定位和適用場景,目的是幫助讀者建立對 UML 整體系統性的認知,而不是過早的陷入 UML 的使用細節裏。我們要應用一項技術或工具,不能單純的因爲它的酷炫或者說業界都在用所以我們要用,而應該結合自己的使用場景以及技術或工具的特點,來確認這項技術或工具究竟是不是我們需要的。

在讀者瞭解 UML 在面向對象分析設計領域優秀的特性之後,我們再來看看 UML 的一些細節。

凡是語言,都會存在基本詞彙和語法。

那麼對應到 UML 裏,基本詞彙就是核心元素,語法就是核心視圖。

UML 的組成結構如下圖:

6.1 核心元素

我們先介紹核心元素。

6.1.1 版型

版型:也稱「類型」或「構造型」。是對 UML 元素基礎定義的擴展,在元素基礎定義的基礎上賦予特別的含義,使得這個元素適用於特定的場合。

比如,我們前邊提到的「邊界類」、「實體類」、「控制類」都是類的版型。

6.1.2 參與者

參與者定位:事件的第一驅動者,也是系統的服務方。比如你在電商網站購物,你就是參與者。

6.1.3 用例

用例定位:系統執行的一系列操作,並生成參與者可以觀察的值。比如你在電商網站交易,會生成在線訂單,用戶下單就是一個用例。

用例版型:

你會發現,同是用例的版型,業務用例與系統用例的區別就在於業務用例是客戶業務視角,系統用例是系統視角。

6.1.4 邊界

邊界定位:用於業務建模和系統建模階段的分析,保證分析粒度在一定的範圍內,不會擴散。

比如一個電商網站按領域職責作爲邊界,會有店鋪域、商品域、會員域、交易域、支付域和營銷域等。各域只負責域內的事情,就能夠減少混亂緊耦合的局面。

一個好的分析和設計如同一筐帶殼的雞蛋,清清爽爽;一個差的設計如同一堆打碎了殼的雞蛋,粘粘糊糊。殼,是好壞的關鍵。

6.1.5 業務實體

業務實體定位:它代表參與者執行業務用例時所處理或使用的事物,特別用於在業務建模階段建立領域模型。業務實體是類(class)的一種版型。

業務實體的結構:包含屬性和方法。屬性用來保存業務實體特徵,方法用來訪問業務實體。比如一臺電視,把它看成一個業務實體的話,它的屬性有運行狀態和音量,它的方法就是遙控器,我們可以開、關、調聲音,但是我們不可以試圖讓它飛起來——因爲它沒有這樣的方法。

6.1.6 包

包定位:容納併爲其他 UML 元素分類。比如 Java 後端經常會提供 jar 包給接入方使用。

6.1.7 分析類

分析類定位:用於代表系統中主要的職責簇,由此產生系統的設計類和子系統。

分析類的抽象層次較高,比設計和實現要穩定很多,因此方便維護,也更容易獲得一個穩定架構來指導整個軟件的開發。

6.1.8 設計類

設計類定位:是系統實施中一個或多個對象的抽象,由此映射到實現代碼,依賴於實施語言。

設計類結構:

6.1.9 關係

關係定位:抽象出對象之間的聯繫,讓對象構成某個特定的結構。

關係分爲以下幾種:

關聯(association)

依賴(dependency)

泛化(generalization)

實現(realization)

聚合(aggregation)

組合(composition)

關聯關係和依賴關係的區別:關聯關係是靜態天然的聯繫,依賴關係是動態臨時的聯繫。

此外還有隻用於用例中的關係:

擴展(extends)

包含(include)

6.1.10 組件

組件定位:實現特定功能的邏輯代碼模塊。比如分佈式應用架構下,將業務目標拆成多個功能,每個功能作爲組件獨立部署。這樣這些組件也能被其他場景複用。

6.1.11 節點

節點定位:表示應用程序的部署單元。比如分佈式應用的環境中,服務器或設備會有很多,就需要通過節點來體現物理部署的情況。

6.2 核心視圖

前面我們介紹了 UML 的核心元素,這些元素分別應用於面對對象分析設計的各個階段,正是它們之間的相互組合,才形成了 UML 裏的各種視圖,最終指導軟件設計。

接下來講講核心視圖裏的結構視圖和行爲視圖,下圖是大綱。

6.2.1 結構視圖

結構視圖也稱爲靜態視圖。靜態視圖就是表達靜態事物的。它只描述事物的靜態結構,而不描述其動態行爲。這裏簡要介紹的靜態視圖包括用例圖,對象圖,類圖,組件圖,包圖和部署圖。

6.2.1.1 用例圖

用例圖包含參與者、用例和關係這三種核心元素,不同的視角可以得到不同的用例視圖,它展現了系統的功能性需求。

所謂不同的視角,可以對應面向對象分析設計的三階段。

就借閱圖書的用例而言,業務用例視圖如下,它是完全從業務角度出發,和計算機系統無關。

而我們在業務用例分析的過程中,可以分解出一些關鍵的概念用例,並建立它們之間的關係,如下圖(bu 表示業務用例,cu 表示概念用例)。

我們對業務用例進行分析以後,就可以繪製系統用例視圖。但不是所有的業務用例都有系統用例對應,比如檢查借閱證可能是手工工作,就不需要納入系統建設範圍。

下圖是借閱圖書的系統用例視圖。

6.2.1.2 類圖

類圖用於展示系統中的類及其相互之間的關係。

類圖建模常用的方式是從概念層,到說明層,最後到實現層這麼一個抽象層次逐步降低和細化的過程。

概念層類圖位於業務建模階段,這個階段採用業務實體這個核心元素來表示。

下圖是網上購物的業務實體圖。

網上購物主要由商品、訂單、支付賬戶這幾個關鍵類構成,這幾個類的交互能夠完成網上購物這個業務目標。

說明層類圖位於概念建模階段,這個階段採用分析類這個核心元素來表示。

下圖展示了網上購物的說明層類圖,這個類圖表達了從計算機的視角來說,網上購物這個業務目標是由哪些類來完成的,這些類的接口保證了這個業務目標的達成。

實現層類圖位於設計建模階段,這個階段採用設計類這個核心元素來表示。

到了這一層,類圖可視作僞代碼,因此,在這個層次上,類必須明確採用哪種實現語言、什麼設計模式、什麼通信標準、遵循什麼規範等。

下圖展示了查詢商品功能的類圖。可以看到,到了實現層類圖,類描述和類關係已經是僞代碼級別了。

由此可見,在軟件生命週期的不同階段,類圖也有三種不同的表達,他們分別是概念層類圖,說明層類圖和實現層類圖。

很多朋友在建模的時候只會用到實現層類圖,並非他們對問題領域足夠了解,而是不清楚類圖也分了這麼三層。

6.2.1.3 對象圖

對象圖是類圖的實例,標識和類圖基本相同。由於對象存在生命週期,對象圖只能在系統某一時間段存在,因此對象圖可以被想象成正在運行的系統在某一時刻的快照。

比如一個正在運行的列車,如果用對象圖來描述,某個時間點你會發現以下靜態圖片:

6.2.1.4 包圖

在實際的項目中,建模過程獲得的元素可能是非常多的,如果將這些元素的關係都繪製出來,看上去就會特別亂,特別複雜,也難以識別。

那爲了更好的理解和管理這些建模元素,我們就需要有規律的對元素進行組織。包圖就起到了這麼一個作用,通過包這個容器,可以從大到小、從粗到細地將建模元素組織起來,便於我們的分析,交流和細化。

下圖是網上購物的領域包圖,它表達了關鍵業務領域及其依賴關係。

下圖展示了查詢商品功能的類層次,它表達了實現類位於哪個層次的軟件架構的觀點。

6.2.1.5 組件圖

當有些包能夠被多個場景重複使用,那這個包就可以認爲有着特定的功能,能夠完成特定的目標。

這種情況下,包就可以定義爲組件,組件是一種特殊的包,既起到了普通包組織和容納的作用,又能完成特定的功能。

比如模塊(登錄模塊),類庫(Java Guava 包)。

下圖可以表達組件實現的過程,通過第三方軟件或者面向對象分析設計過程中產生的各種包,可以定義組件。

組件可以按功能分爲以下幾類:模塊、子系統、庫、可執行文件和程序包等等。

6.2.1.6 部署圖

部署圖描述了物理上系統運行時的結構,包括系統中硬件的分佈以及軟件部署到硬件上的具體方式。

部署圖用於設計建模階段,採用節點和關係兩種核心元素來繪製。常用於分佈式應用環境和多設備應用環境。

上圖是一個簡單的部署圖,表達了客戶端比如瀏覽器這個節點,會請求到 Web 服務器節點,最後通過數據庫服務器節點返回數據。如果涉及分佈式環境,就要考慮多個 Web Server,多個 Database Server,甚至考慮多機房,異地等物理層面的部署方式。

結構視圖介紹完,我們講講行爲視圖。

6.2.2 行爲視圖

行爲視圖也稱爲動態視圖。動態視圖就是描述事物動態行爲的。動態視圖不能獨立存在,它必須基於一個靜態視圖或者 UML 元素,說明在靜態視圖規定的事物結構下它們的動態行爲。

這裏簡要介紹的動態視圖包括狀態圖、活動圖、時序圖和協作圖。

6.2.2.1 狀態圖

狀態圖也稱狀態機,它描述了一個對象的生命週期,你可以把它理解成一臺運行中的機器,這臺機器負責這個對象在固定幾個狀態間的流轉。

這個對象可以是業務實體對象,也可以是分析類對象,還可以是設計類對象。也就是說,在面向對象分析設計的三個階段(業務建模,概念建模,設計建模),都可以用狀態圖來表達。

下圖是一個產品的生命週期狀態圖。綠色部分是狀態圖相關的元素,紅色部分是元素的解釋。

從圖中,我們可以看到,狀態圖有以下關鍵元素:

  1. 初始狀態:它是狀態機的起始位置,不需要事件的觸發。用實心圓圈表示;

  2. 狀態:狀態是對象執行某項活動或者等待某個事件時的條件。比如要想執行產品入庫動作,產品得是未入庫的狀態,如果想銷售某個產品,產品得是入庫的狀態;

  3. 轉移:轉移是兩個狀態之間的關係,它表示當發生指定事件並且滿足指定條件時,第一個狀態中的對象將執行某些操作並進入第二個狀態。比如產品入庫這個動作,就將產品的狀態從未入庫轉移到了已入庫;

  4. 事件:事件是一個特定的動作或行爲,有時候也包括系統時鐘之類的定時器。如果條件滿足,事件的發生將觸發一個轉移。比如產品銷售這個動作,出發產品從已入庫狀態轉移至已銷售狀態;

  5. 條件:條件是一個布爾表達式,當事件發生時將檢查這個表達式的值。條件求值結果可能決定轉移的分支,或者拒絕轉移。條件有可能引用當前狀態。比如產品合不合格這個布爾判斷,決定了產品是可被銷售,還是不可被銷;

  6. 最終狀態:最終狀態表示狀態機執行結束,或者對象生命週期結束。用帶環的實心圓圈表示。

6.2.2.2 活動圖

活動圖描述了爲了完成某一個目標需要做的活動以及這些活動的執行順序。

UML 中有兩個層面的活動圖,一種是用例活動圖,它用於描述用例場景,常用於業務建模階段,另一種是對象活動圖,用於描述對象交互,常用於設計建模階段。

下圖是一個登機手續辦理的用例活動圖。綠色部分是活動圖相關的元素,紅色部分是元素的解釋。

從圖中,我們可以看到,活動圖有以下幾個關鍵元素:

用例活動圖常常是從業務的角度上,分析要完成某個目標,要執行哪些活動。如果在系統設計的角度上,要表達完成目標需要的活動,就需要用到對象活動圖。

比如根據查詢商品的對象交互過程,就能繪製出以下的對象活動圖。

雖然 UML 允許用活動圖繪製對象交互,但實際工作中,我從來沒用過。因爲 UML 有其他更好的工具來繪製對象交互圖,比如接下來要講的時序圖。

6.2.2.3 時序圖

時序圖用於描述按時間順序排列的對象之間的交互模式。

前面類圖那一節有提過類有三個層次的觀點:概念層、說明層和實現層,分別對應於面向對象分析設計的業務建模階段、概念建模階段和設計建模階段,相應的,也可以在這三個層次上分別對業務實體對象、分析類對象和設計類對象繪製業務模型時序圖、概念模型時序圖和設計模型時序圖。

接下來介紹三種時序圖

業務模型時序圖用於爲領域模型中的業務實體交互建模,目標是實現業務用例。

上一節提到的活動圖,可以幫助我們發現業務實體,活動圖也可以很輕易的轉換成時序圖,下圖是網上購買商品的業務模型時序圖。

時序圖中會涉及一些 UML 元素,這裏列舉常用的幾個:

業務模型時序圖是業務建模階段的產物,它展現了業務的實際需求,因此使用的描述語言應當採用業務術語。

進入概念建模階段,可以採用分析類繪製概念模型時序圖。和業務模型時序圖相比,同樣是展現業務需求,不同點在於分析類代表了系統原型,所以這個階段的時序圖已經帶有了計算機層面的理解。

因此,概念模型時序圖既保留了實際業務需求,又得到了計算機實現的基本理念。如下圖所示。

可以看到,在概念模型時序圖裏,相對於業務模型時序圖,我們的表達增加了安全認證和商品目錄。這是因爲我們實際在做登錄這個功能時,我們的軟件系統需要關心身份覈驗。我們在獲取商品時,爲了避免雜亂需要對其進行分類。

另外,我們的業務實體轉爲分析類進行表達,網站作爲邊界類,用於隔離用戶操作和系統行爲。安全認證作爲控制類,用於決定是否能成功登錄網站。商品目錄和商品作爲實體類,用於表達用戶實際想看到或者操作的實體信息。

分析類展示出來的已經是系統實現的原型,進入設計建模階段,我們做的工作就是要選擇合適的實現方式來實現這個原型。

設計建模階段,我們採用設計模型時序圖來實現概念模型中的交互。

設計模型時序圖使用設計類作爲對象繪製,也是我們日常開發設計中最爲常用的動態視圖。以下是商品查詢的設計模型時序圖。

可以看到,在設計模型時序圖裏,消息會細緻到方法級別。因爲在這個階段,相關的技術選型,比如編程語言,交互協議,中間件等已經比較明確了。

時序圖除了在建模的三個階段使用外,當你需要表達對象的交互,或者想分析對象的職責和接口時,都可以使用時序圖。

6.2.2.4 協作圖

協作圖和時序圖一樣,也是描述對象之間的交互模式,不同的是,時序圖在意的是對象交互的執行順序,而協作圖在意的是對象間的結構關係。

因此,時序圖適用於獲得對調用過程的理解,而協作圖適用於獲得對對象結構的理解。

協作圖可以和時序圖互相轉換,對應時序圖的三種表達方式,協作圖也分爲業務模型協作圖,概念模型協作圖和設計模型時序圖。本文只介紹業務模型協作圖,另外兩種協作圖可以由相應的時序圖推導,這裏就不贅述了。

業務模型協作圖同樣採用業務實體來繪製,目標也是實現用例場景。下圖是網上購買商品的業務模型協作圖。

可以看到,協作圖和時序圖相比,對象間的結構一目瞭然,很容易知道哪些消息會影響哪些對象或者哪些對象需要提供哪些接口。但在執行順序的表達上就很弱,必須依賴消息文本里的數字。

以下是協作圖常用的 UML 元素:

6.2.3 小結

本節介紹了 UML 的核心視圖,我們再看下核心視圖的大綱。

核心視圖分靜態視圖和動態視圖。靜態視圖表達事物的結構性觀點,動態視圖表達事物的行爲性觀點。

一個好的建模,結構性和行爲性都不可或缺,既要說明該事物長什麼樣子,又要說明該事物應該怎麼用。

  1. 總結

本文從一個示例開始,引入了 UML 的概念,介紹了什麼是 UML,爲什麼要用 UML 以及什麼時候用 UML。我們瞭解一個事物,知其然也要知其所以然。

然後介紹了 UML 的組成結構,從元素和視圖的角度出發,講解了繪製圖形的方法和相關概念。文中也給出了很多我親手繪製的樣例視圖,如有錯誤之處,還望讀者指摘。

紙上得來終覺淺,絕知此事要躬行。知道和做到總有一段距離,重在實踐。

關注「ImportNew」,提升 Java 技能

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/FeDV-dWlPbaHZJSurkoabw