天天看點

UML入門以及Plant UML工具介紹

簡介

UML,Unified Modeling Language,統一模組化語言,是一種開放的方法,用于說明、可視化、建構和編寫一個正在開發的、面向對象的、軟體密集系統的制品的開放方法。——維基百科

模型

  • 功能模型:從使用者的角度展示系統的功能,包括:用例圖
  • 對象模型:采用對象,屬性,操作,關聯等概念展示系統的結構和基礎,包括:類圖、對象圖
  • 動态模型:展現系統的内部行為。包括:序列圖,活動圖,狀态圖

UML制作工具

  • IBM Rational Rose
  • StarUML
  • EA
  • ​​processon​​:線上協作繪圖平台,為使用者提供最強大、易用的作圖工具,支援線上創作流程圖、BPMN、UML圖、UI界面原型設計、iOS界面原型設計、泳道圖等。可共享友善團隊協作,但有隻能繪制9張圖的限制,導出檔案不可編輯
  • ​​draw.io​​:功能超級強大,支援幾十種繪圖類型,免費可用
  • Plant UML:基于graphviz的一款強大的繪圖工具
  • ​​planttext​​:線上繪圖,支援導出,可以自建一個伺服器生成圖檔。好處是不用儲存圖檔,可以直接應用生成的圖檔位址
  • ​​gravizo​​:同樣基于graphviz

類圖

類圖是UML的靈魂。想要畫好類圖,就要學會給類圖分出不同的組,分成不同的包。分組的規則就是跟三層架構的層是一一對應的。純三層——UI、BLL、DAL這三層再加上一個Entity(實體)層。

  • UI層

    使用者界面對應的類。這些窗體類一般既沒有方法也沒有屬性,它們隻是通過事件(如單擊事件等)來調用 BLL 層裡面的方法。

  • Entity層

    實體層裡面的類跟資料庫裡面的表是一一對應的,即一張表一個實體類,實體類同樣沒有方法,但是它有自己的屬性。它的屬性就是表裡面每一列的每個字段。

  • DAL層

    用來跟資料庫打交道,是以它跟實體層一樣,也是與資料庫中的表是一一對應的。而它所具有的方法就是對資料簡單的增删改查。

  • BLL層

    Business Logic Layer:這一層就是上面三個層之間的一個橋梁,負責它們之間的資料交換,通常情況隻有方法沒有屬性,其方法就是窗體所具有的功能(一個功能可能包含一個或多個方法)。

類圖是軟體工程的統一模組化語言一種靜态結構圖,該圖描述系統的類集合,類的屬性和類之間的關系。是系統分析和設計階段的重要産物,也是系統編碼和測試的重要模型依據。

在UML類圖中,類使用包含類名,屬性,方法名及其參數并且用分割線分隔的長方形表示。通過Person的類圖,可以看出類圖有三部分組成,類名,屬性和方法。若是抽象類,在類名右上角會有一個​

​{abstract}​

​表示。

UML入門以及Plant UML工具介紹

UML中的屬性名就是Java中的成員變量。Java類中成員變量的修飾符,類型和預設值都可以在UML類圖中展現出來。通用表示方法如下:​

​可見性 名稱:類型 [ = 預設值 ]​

​​ Java中類的成員變量或方法的可見性有3種:private,public 和protected,類圖中分别用符号​

​-​

​、​

​+​

​和​

​#​

​表示。

通用表示方法中名稱就成員變量的名字,類型就是成員變量的類型,可以是自定義類型。而後面的預設值是可選參數,如果沒有給成員變量設定初始值,UML類圖中就不顯示;

操作方法:​

​可見性 名稱(參數清單) [ : 傳回類型]​

​ 類的操作方法通用表示方式如上,方法可見性和屬性可見性是一緻的,名稱就是方法名,參數清單是可選項,若多個參數用英文逗号隔開,傳回類型是一個可選項,表示方法的傳回值類型,依賴于具體的程式設計語言,可以是基本資料類型,也可以是使用者自定義類型,還可以是空類型(void);構造方法,則無傳回類型。

類之間的關系

  • 泛化(Generalization)
  • 實作(Realization)
  • 依賴(Dependency)
  • 關聯(Association)
  • 聚合(Aggregation)
  • 組合(Composition)

另有一說,類的關系有泛化、實作、依賴和關聯,關聯又分為一般關聯關系和聚合關系、組合關系。

泛化

泛化(又叫繼承),is-a的關系,表示一個對象是另外一個對象的意思,也就是Java中的繼承。泛化是對象之間耦合度最大的一種關系,子類繼承父類的所有細節。類和類,接口和接口都可以是繼承關系,父類又稱作基類或超類,子類又稱作派生類,類繼承父類後可以實作父類的是以功能,并能擁有父類沒有的功能。用帶空心三角形的直線來表示,箭頭從子類指向父類。最終代碼中,泛化關系表現為一個類繼承一個非抽象類。如:​

​Father <|-- Son​

實作

實作,在java中就是一個接口和實作類之間的關系,接口中一般是沒有成員變量,所有操作都是抽象的,隻有聲明沒有具體的實作,具體實作需在實作該接口的類中。在UML中用與類的表示法類似的方式表示接口,差別可在UML中類圖中看出。用虛線和帶空心的三角形表示,箭頭從實作類指向接口。示例:

abstract class AbstractList
interface List
List <|.. AbstractList      

依賴

依賴,是類與類之間最弱的關系,依賴可以簡單的了解一個類使用另一個類,這種使用關系具有臨時性特征,但一個類又會由于另一個類的改變而受到影響。表現在代碼層面,為類B作為參數被類A在某個method中使用,一般指由局部變量、函數參數、傳回值建立的對于其他對象的調用關系。一個類調用被依賴類中的某些方法而得以完成這個類的一些職責。用帶箭頭的虛線表示依賴,箭頭從使用類指向被依賴的類。

如:​​

​Human ..> Cigarette​

關聯

關聯,描述不同類的對象之間的結構關系;它是一種靜态關系, 通常與運作狀态無關,一般由常識等因素決定的;一般用來定義對象之間靜态的、天然的結構;是一種強關聯的關系。這種關系通常使用類的屬性表達。關聯又分為一般關聯、聚合關聯與組合關聯。表現在代碼層面,為被關聯類B以類屬性(成員變量)的形式出現在關聯類A中。表示一個類和另一類是一種包含關系。用帶箭頭的實線表示,箭頭指向被包含類(箭頭從使用類指向被關聯的類)。分為:​

​1..1​

​​ 表示另一個類的一個對象隻與該類的一個對象有關系,​

​0..* ​

​​表示另一個類的一個對象與該類的零個或多個對象有關系,​

​1..*​

​​ 表示另一個類的一個對象與該類的一個或多個對象有關系,​

​0..1​

​​ 表示另一個類的一個對象沒有或隻與該類的一個對象有關系,​

​*​

​ 任意多個對象關聯。關聯關系預設不強調方向,表示對象間互相知道。

class Water
class Human
Human --> Water      

聚合

聚合,關聯關系的一種特例,表示整體與部分、擁有的關系,即​

​has-a​

​的關系,此時整體與部分之間是可分離的,他們可以具有各自的生命周期。但是部分可以脫離整體而存在。用帶空心菱形的直線表示,菱形從局部指向整體。如:​

​Company o-- Human​

組合

組合,關聯關系的一種特例,展現一種 ​

​contains-a(has-a)​

​ 關系,一種強烈的包含(擁有)關系,比聚合更強,也稱為強聚合;同樣展現整體與部分間的關系,但此時整體與部分是不可分的,整體的生命周期結束也就意味着部分的生命周期結束。此時部分需在整體的構造方法中建立。組合關系是一種強依賴的特殊聚合關系。組合關系用帶實心菱形的直線表示,菱形從局部指向整體。如:​

​Human *-- Brain​

​​ 注:多重性(Multiplicity) : 通常在關聯、聚合、組合中使用。代表有多少個關聯對象存在。使用​

​數字..星号(或者數字)​

​表示。詳情見上面的關聯關系。

總結

繼承、實作這兩種關系,展現的是一種類與類、或者類與接口間的縱向關系;其他四種關系則展現的是類與類、或者類與接口間的引用、橫向關系,是比較難區分的,有很多事物間的關系要想準備定位是很難的,這幾種關系都是語義級别的,是以從代碼層面并不能完全區分各種關系;其中聚合群組合尤其難區分。

總的來說,後幾種關系所表現的強弱程度依次為:組合 > 聚合 > 關聯 > 依賴。

聚合群組合的差別

聚合是has-a關系,組合是contains-a關系;聚合關系表示整體與部分的關系比較弱,而組合比較強;聚合關系中代表部分事物的對象與代表聚合事物的對象的生存期無關,一旦删除聚合對象不一定就删除代表部分事物的對象。組合關系中一旦删除組合對象,同時也就删除代表部分事物的對象。

組合和繼承

封裝、繼承、多态是面向對象的三個特征;Java代碼的複用有繼承,組合以及代理三種具體的表現形式,繼承可以實作類的複用。是以,很多開發人員在需要複用一些代碼的時候會很自然的使用類的繼承的方式。但是長期大量的使用繼承會給代碼帶來很高的維護成本。

在繼承結構中,父類的内部細節對于子類是可見的。是以通常也可以說通過繼承的代碼複用是一種白盒式代碼複用。(如果基類的實作發生改變,那麼派生類的實作也将随之改變。這樣就導緻子類行為的不可預知性;)

組合是通過對現有的對象進行拼裝(組合)産生新的、更複雜的功能。因為在對象之間,各自的内部細節是不可見的,是以也說這種方式的代碼複用是黑盒式代碼複用。(因為組合中一般都定義一個類型,是以在編譯期根本不知道具體會調用哪個實作類的方法)

繼承,在寫代碼的時候就要指名具體繼承哪個類,是以,在編譯期就确定關系。(從基類繼承來的實作是無法在運作期動态改變的,是以降低應用的靈活性。)

組合,在寫代碼的時候可以采用面向接口程式設計。是以,類的組合關系一般在運作期确定。

對比

組合關系 繼承關系
優點:不破壞封裝,整體類與局部類之間松耦合,彼此相對獨立 缺點:破壞封裝,子類與父類之間緊密耦合,子類依賴于父類的實作,子類缺乏獨立性
優點:具有較好的可擴充性 缺點:支援擴充,但是往往以增加系統結構的複雜度為代價
優點:支援動态組合。在運作時,整體對象可以選擇不同類型的局部對象 缺點:不支援動态繼承。在運作時,子類無法選擇不同的父類
優點:整體類可以對局部類進行包裝,封裝局部類的接口,提供新的接口 缺點:子類不能改變父類的接口
缺點:整體類不能自動獲得和局部類同樣的接口 優點:子類能自動繼承父類的接口
缺點:建立整體類的對象時,需要建立所有局部類的對象 優點:建立子類的對象時,無須建立父類的對象

如何選擇

面向對象中有一個比較重要的原則『多用組合、少用繼承』或者說『組合優于繼承』。組合确實比繼承更加靈活,也更有助于代碼維護。

是以,建議在同樣可行的情況下,優先使用組合而不是繼承。因為組合更安全,更簡單,更靈活,更高效。

并不是說繼承就一點用都沒有,前面說的是【在同樣可行的情況下】。有一些場景還是需要使用繼承的,或者是更适合使用繼承。

繼承要慎用,其使用場合僅限于你确信使用該技術有效的情況。一個判斷方法是,問一問自己是否需要從新類向基類進行向上轉型。如果是必須的,則繼承是必要的。反之則應該好好考慮是否需要繼承。《Java程式設計思想》

隻有當子類真正是超類的子類型時,才适合用繼承。換句話說,對于兩個類A和B,隻有當兩者之間确實存在is-a關系的時候,類B才應該繼續類A。《Effective Java》

其他類型

時序圖

通過描述對象之間發送消息的時間順序顯示多個對象之間的動态協作,即對象之間的消息流動順序。​

​->​

​​表示消息傳遞,​

​-->​

​​表示異步消息傳遞,​

​note [left | right]​

​ 對消息進行說明。垂直的虛線叫做生命線,代表一個對象的存在時間。每個箭頭都是一個調用,生命線上白色的條叫做激活條,代表這次調用持續的時間。

特點

  1. Sequence Diagram是強調消息時間
  2. 順序的互動圖
  3. 時序圖描述類系統中對象和對象之間的互動
  4. 時序圖是一個模型,用于描述對象組如何随着時間在某些行為方面互動

元素

  • 角色(Actor)
  • 對象(Object)
  • 生命線(Lifeline)
  • 消息(Message)
  • 自關聯消息(Self-Message)

總結

  1. 時序圖隻描述理想的工作流程
  2. 時序圖工具沒有角色,可以在用例圖中建立角色,然後再把項目中的角色拖入到時序圖中

使用者登陸執行個體:

UML入門以及Plant UML工具介紹

用例圖

參與者與用例的互動,主要作用是來收集系統需求,包括内部和外部的影響(例如此系統的使用者分為n種角色,每一個角色所能幹的事)。

用例圖的2種元素

  • 參與者Actor
  • 用例use Case

4種關系

  • 關聯關系association:參與者與用例之間進行通信,不同的參與者可以通路相同的用例,盡量避免關聯線交叉
  • 包含關系include:客戶用例可以簡單地包含提供者用例具有的行為,并把它所包含的用例行為作為自身行為的一部分
  • 拓展關系extend:
  1. 擴充用例被定義為基礎用例的增量擴充并在一定條件下發生
  2. 基礎用例提供擴充點以添加新的行為
  3. 擴充用例提供插入片段以插入到基礎用例的擴充點上
  • 泛化關系generalization:描述多個參與者之間的公共行為

用例之間的關系

  • 關聯關系
  • 包含關系
  • 拓展關系

總結

  1. 外部可見的系統功能單元(用例圖可分級别)
  2. 不是需求或功能的規格說明,隻展示和展現其所描述需求本身的情況
  3. 用例圖最好的方法就是從分析系統的參與者開始,考慮每個參與者是如何使用系統的
  4. 給使用者看的,避免使用專業術語

活動圖

當流程圖來用,描述程式的處理過程。

元件圖

表示元件是如何互相組織以建構更大的元件或是軟體系統。

狀态圖

描述對象從開始到結束的狀态改變。

執行個體:

[*] -> ready : start;
ready -> running : get cpu;
running -> ready : lost cpu;
running -down-> block : io, sleep, locked;
block -up-> ready : io return, sleep over, get lock;
running -> [*] : complete;      

效果:

UML入門以及Plant UML工具介紹

plant UML

簡介

Plant UML是一門類似于HTML的标記性語言,采用graphviz來渲染PlantUML,可內建在markdown。故而可以像維護代碼一樣維護 UML 圖的曆史版本,編寫腳本就會自動生成UML圖。用于會議讨論、流程設計、需求編寫等環節。支援的工具集​​tools​​​ 不要太多!同時提供線上版工具:​​online-plantuml​​。

PlantUML是一個快速建立UML圖形的元件,其支援的圖形有:

  • sequence diagram
  • use case diagram
  • class diagram
  • activity diagram
  • component diagram
  • state diagram
  • object diagram
  • wireframe graphical interface

安裝

Plant UML 依賴 Graphviz:

  • Windows下載下傳安裝​​graphviz​​,選擇 msi 安裝包或 zip壓縮包;
  • Mac 安裝:​

    ​brew install graphviz​

    ​。

無論是 sublime 還是 IDEA 想要借助Plant UML繪制 UML 圖,都需要先安裝 Graphviz。

PlantUML 提供 IDEA 插件:plantuml integration,安裝好後重新開機IDEA。在 IDEA other setting 中更改配置即可。

UML入門以及Plant UML工具介紹

sublime 安裝 plantUML 參考我的部落格:​​Sublime 入門使用教程​

入門

建立一個文本檔案,如​

​demo.txt​

​(字尾名随意):

@startuml
    ' 單引号開頭,注釋内容
    /' 另一種形式的注釋 '/
    ' 執行個體展示類圖通路權限控制:- # ~ + 分别表示 private、protected、package、public
    ' 使用 skinparam classAttributeIconSize 0關掉icon的顯示;
    ' 使用{static}或者{abstract}來修飾字段或者方法,修飾符需要在行開頭或者末尾;可以使用{classifier}代替{static}
    ' 加粗:<></b> 換行:\n 該表字型 font 大小: <size:nn>
    ' 使用 title 或者 title end title 表明标題
    title some silly example\n showing <b>Plant UML</b> title

    class SampleClass {
       {static} - private field1
       {abstract} # protected field2
        ~ package method1()
        + public method2() {classifier}
    }

    ' 在類名後面添加冒号可以添加方法和方法的參數
    Object <|-- ArrayList
    Object : equals()
    ArrayList : Object[] elementData
    ArrayList : size()

    ' 可以改變箭頭方向, 也可以在箭頭上使用left, right, up or down關鍵字,關鍵字可以使用開頭的幾個字元簡寫,如使用-d-代替-down-。

@enduml      

渲染效果圖:

UML入門以及Plant UML工具介紹

其他UML示例參考​​GitHub​​,也可以在 Chrome 中安裝Plant UML 插件的形式來內建使用。

文法

參考