簡介
背景
本文介紹如何使用Graphviz package的dot工具動態生成UML圖,涵蓋了UML類圖的包、類、屬性、方法、關係建模。當然,本文僅僅描述手工創建UML圖描述的場景,但在通過工具分析代碼結構時將變得非常有用,尤其是要創建一個類似於UMLGraph的軟件時,所以,繼續往下讀吧~
開始
準備工作
首先,從Graphviz website下載Graphviz工具包,根據使用操作系統的差異,進行直接安裝或編譯安裝,Linux用戶可以直接通過包管理工具獲取。準備工作結束,通過例子去認識瞭解它將是直接而高效的,本文將使用這種方式,還有就是,安裝Bitstream Vera字體,因爲本文一直用它~
所謂的“問題”
例子基於動物世界的一角,建模一個superclass:Animal,有兩個subclasses:Dog、Cat,動物有attributes、methods,並且Dog、Cat會添加method關聯起來。我們會建模Dog、Cat之間N:M的死敵association,另外,Animal類在默認的package,而Dog、Cat在"animal.impl“包中。
打開一個文本編輯器,開始吧~~~
繪圖基礎
常規屬性
先爲dot工具寫一個樣板:
digraph G { fontname = "Bitstream Vera Sans" fontsize = 8 node [ fontname = "Bitstream Vera Sans" fontsize = 8 shape = "record" ] edge [ fontname = "Bitstream Vera Sans" fontsize = 8 ]
不用擔心沒看明白,第一行指我們要繪製一個directed graph,簡稱爲digraph;一個directed graph是指一個這樣的圖:圖中的每個邊都是從一個節點指向另外一個節點,每個邊都有一個開始節點和結束節點;第二、三行設置了圖中文字使用的字體、大小,接下來的幾行設置了節點、邊所使用的默認字體屬性,上面的代碼並不完整,缺少一個重要的信息:爲節點定義shape屬性。
通過設置節點的shape類型爲record,可以很好的使用橫槓分割一個節點來展示一個UML的類圖。
建模Animal類
建模一個Animal類,有兩個共有屬性:name、age,一個公有方法:die(),作爲一個簡單的例子,這樣足夠了,建模爲:
Animal [ label = "{Animal|+ name : string\l+ age : int\l|+ die() : void\l}" ]
如果你沒有看懂dot的語法,我有點無奈了,dot解析後的類圖如下:
怎麼做到的?
設置的label屬性做了如下幾件事情:
- "{"、"}"表示創建一個包含多個分割段的"record" shape;
- 管道"|"表示分割符,一個用來分割類名、類屬性,一個用來分割類屬性、類函數;
- "\|"用來從當前位置回車換行,並從左側開始顯示;
試一下吧!
創建一個文件”class.dot“,並複製粘貼下面的代碼:
digraph G { fontname = "Bitstream Vera Sans" fontsize = 8 node [ fontname = "Bitstream Vera Sans" fontsize = 8 shape = "record" ] edge [ fontname = "Bitstream Vera Sans" fontsize = 8 ] Animal [ label = "{Animal|+ name : string\l+ age : int\l|+ die() : void\l}" ] }
打開命令行,將當前目錄切換到”class.dot“所在目錄,執行如下命令:
dot -T png -o class.png class.dot
將會生成一個Animal類的PNG文件(譯註:可能會因爲不支持png提示失敗,可以換成jpg、svg啥的試下),餘下內容將假設你對dot文件的格式懂了,只展示模型的內容。
繼續建模
創建Dog、Cat類
Dog、Cat類很簡單,在Animal類的後面追加如下內容:
Dog [ label = "{Dog||+ bark() : void\l}" ] Cat [ label = "{Cat||+ meow() : void\l}" ]
執行dot命令後,生成的沒有association的類圖如下:
建模子類之間的關係
Dog和Cat是Animal的子類,讓我們添加UML中的類繼承關係:從Dog、Cat指向Animal的空箭頭,將如下代碼追加到Cat後面:
edge [ arrowhead = "empty" ] Dog -> Animal Cat -> Animal
其中,在第二行將箭頭設置爲空,在下面的”->“表示有方向的關聯,Dog、Cat繼承自Animal,類圖如下:
建模“死敵”關係
通過在子類關係代碼後面追加如下代碼,來表示Dog和Cat直接的死敵關係:
edge [ arrowhead = "none" headlabel = "0..*" taillabel = "0..*" ] Dog -> Cat
第二行將邊上的箭頭去掉了,因爲association沒有呈現指向,"headlabel"、"taillabel"表示邊的起始、結束描述信息;在N:M關係中,都是"0..*",最後一行添加了Dog、Cat類之間的一條邊,dot執行後的結果如下:
建模package
添加包需要在聲明Dog類的前面添加如下兩行,並在Cat類的後面添加"}":
subgraph clusterAnimalImpl { label = "Package animal.impl"
第一行告訴dot包括的節點需要在一個集合框中展示,第二行描述了這個集合框的標題;subgraph表示一個集合的開始,只有關鍵字:subgraph纔會被識別。
結論
最終的樣子
最終dot文件的內容如下:
digraph G { fontname = "Bitstream Vera Sans" fontsize = 8 node [ fontname = "Bitstream Vera Sans" fontsize = 8 shape = "record" ] edge [ fontname = "Bitstream Vera Sans" fontsize = 8 ] Animal [ label = "{Animal|+ name : string\l+ age : int\l|+ die() : void\l}" ] subgraph clusterAnimalImpl { label = "Package animal.impl" Dog [ label = "{Dog||+ bark() : void\l}" ] Cat [ label = "{Cat||+ meow() : void\l}" ] } edge [ arrowhead = "empty" ] Dog -> Animal Cat -> Animal edge [ arrowhead = "none" headlabel = "0..*" taillabel = "0..*" ] Dog -> Cat }
執行生成的UML類圖如下:
更多
系統本文爲您提供了一個通過dot動態繪製UML圖良好的開端,訪問UMLGraph website瞭解更多,希望對你有用。