大家平日在写技术文档时,往往都有画 UML 图的需要,很多人使用 PrecessOn 或者 darw.io 等来绘制 UML ,勉强可用但是不够专业。这里为大家推荐一个专门画UML的工具: PlantUML
1. PlantUMLPlantUML 诞生于 2009 年,知道的人多但是使用的人少。因为它使用特殊的 DSL 进行画图,相较与其他工具,PlantUML 的图不是“画”出来的而是“写”出来的。
虽然有一定学习成本,但是却可以画出更专业的UML图,而且文本格式也便于保存。本文总结 PlantUML 的基本用法,帮助大家快速入门。
安装环境PlantUML 是一个 java 程序,所以有 JDK 就能跑。可以从官网直接下载 jar 文件执行,当然它也提供了 IDEA 和 VSCode 的插件。
需要注意的是,PlantUML 的本地渲染依赖 Graphviz ,需要提前安装并配置环境变量。如果你使用 VSCode 插件,也可以借助云端渲染,只需要作如下配置:
之后就可以在 VSCode 中一边“写” UML 一边预览了。
接下来我们学习如何写出漂亮的 UML ,像学习其他语言一样 从 Hello World 开始。
2. Hello World
//hello.pu @startuml Hello <|-- World @enduml
PlantUML 文件通常以 .pu 为后缀,
命令行指定 pu,
java -jar plantuml.jar hello.pu
在当前目录下会将 @startuml 与 @enduml 之间的部分生成生成同名的 png
除了.pu以外,各种源码文件中的 @startuml 与 @enduml 也能识别并生成 png,
例如 .c,.c++, .htm, .java 等等,因此我们可以将源码配套的 UML 写入到注释中:
public class JavaSource {}
需要注意,一组@startuml/@enduml 对应一张 png,如果一个文件中有多组,则生成的 png 文件名会添加自增数字后缀。 此外也可以紧跟在 @startuml 之后指定文件名
@startuml foo class Foo @enduml @startuml bar class Bar @enduml @startuml baz class Baz @enduml
3. 基本语法
注释
单引号后面跟随的内容是注释
@startuml no-scale ' 这是注释 Hello <|-- World @endumlTitle
title后跟标题
@startuml title Hello Title Hello <|-- World @enduml多行 title
title 与 end title 之间的输入可以换行
@startuml title Hello Title end title Hello <|-- World @enduml标题样式
PlantUML 支持使用 Creole 这种标记语言,来丰富文字样式,Creole 的用法类似 markdown。
参考 :https://en.wikipedia.org/wiki/Creole_%28markup%29
@startuml title * __Hello__ * **World** end title Hello <|-- World @enduml图注
caption之后跟的内容显示为图注
@startuml caption 图1 Hello <|-- World @endumlheader/footer
@startuml header Hello Hello <|-- World footer World @enduml
header footer可以在头部和尾部追加注释。 默认 header 右对齐, footer 居中对齐。
对齐方式@startuml left header Hello Hello <|-- World right footer World @enduml
在 header footer 前加 left center right 可以设置对齐方式
多行 header/footer跟 title 一样, header ... end header , footer ... end footer
@startuml header Hello Header end header Hello <|-- World footer World Footer end footer @enduml放大率
@startuml no-scale Hello <|-- World @enduml @startuml scale-1.5 scale 1.5 Hello <|-- World @enduml @startuml scale-0.5 scale 0.5 Hello <|-- World @enduml
scale 可以为UML设置防大率
4. 类图
Class
@startuml class Hello class World @enduml
class 指定类
Interface@startuml interface Hello interface World @enduml
interface 指定接口
抽象类@startuml abstract class Hello @enduml
abstract class 指定抽象类
枚举@startuml
enum HelloWorld {
ONE
TWO
THREE
}
@enduml
enum 指定枚举, { ... } 定义枚举值
类型关系UML中类型之间有六大关系:
- 泛化(Generalization)
- 实现(Realization)
- 关联(Association)
- 聚合(Aggregation)
- 组合(Composition)
- 依赖(Dependency)
接下来逐一说明:
泛化泛化关系就是类的继承,java 中对应 extends 关键字。
@startuml Child --|> Parent Parent2 <|-- Child2 @enduml
<|-- --|> 指定继承关系
实现实现关系,对应 implements 关键字
@startuml Plane ..|> Flyable Flyable <|.. Plane @enduml
..|>, <|.. , 圆点表示虚线
依赖依赖表示使用关系,java中, 被依赖的对象/类, 以方法参数, 局部变量和静态方法调用的形式出现。比如, 厨师在烹饪的时候看了一眼菜谱, 厨师"使用"了菜谱, 照着它炒完菜后,这种使用关系就结束了(临时性).
@startuml Chef ..> Recipe @enduml关联
关联关系,表示"拥有"。 相比依赖关系的临时性和单向性,关联关系具有长期性、平等性(可双向),所以关联表示的关系比依赖更强。比如现实生活中的夫妻, 师生等关系。长期存在并且是相互的关系。 此外关联可以表示一对一,一对多,多对一,多对多等各种关系。
@startuml Address <-- Husband Husband <--> Wife Husband2 -- Wife2 @enduml
因为比依赖关系更强, 所以是实线+箭头。 双向关联可以省略箭头。
后面两种关系 “聚合” 和 “组合”,都属于关联关系, 用来表示关联关系中整体与部分的关系。java 中 一个 Class 与其成员变量 Class 类型之间就是这种整体与部分的关联关系。
聚合聚合关系相对于组合弱一些,整体与部分是可分离的。 比如部门与员工,部门有许多员工,员工离职了部门仍然存在,不受影响。反之部门解散了,员工可以去其他部门(整体与部分可分离)
@startuml Department o-- Employee @enduml
o 表示空心菱形
组合组合关系中,整体与部分是不可分离的,整体与部分的生命周期保持一致,少了对方自己的存在无意义。例如人体是有四肢组成的,四肢不能脱离人体存在,人体少了四肢也难言完整
@startuml Body "1" *-- "2" Arm Body "1" *-- "2" Leg @enduml
* 表示实心菱形
同时也看到了一对多时的数字表示方法,双引号" 包裹,放在线段与Class之间。 多对多也同样。
最后再总结一下六大关系
| 继承 | 实现 | 依赖 | 关联 | 聚合 | 组合 | |
|---|---|---|---|---|---|---|
| 关系含义 | 功能扩展 | 功能实现 | 使用 | 拥有 | 整体-部分(has-a) | 整体-部分(contains-a) |
| 关系特性 | - | - | 临时性,单向性 | 长期性,可双向(平等性) | 整体与部分可分离 | 整体与部分不可分离,生命周期一致 |
| java语法 | extends | implements | 方法参数,局部变量,静态方法调用 | 成员变量 | 成员变量 | 成员变量 |
| 关系强弱 | 强 | 强 | 弱 | 较强 | 较强 | 非常强 |
| 现实事例 | 父子 | 飞机/鸟可以飞 | 厨师使用菜谱 | 夫妻,师生 | 部门-员工 | 人体-四肢 |
| 图形指向 | 箭头指向父类 | 箭头指向接口 | 箭头指向被使用者 | 指向被拥有者,可双向 | 箭头指向部分, 菱形指向整体 | 箭头指向部分,菱形指向整体 |
@startuml
interface One
interface Two
interface Three extends Two
interface Four
class Five implements One, Three
class Six extends Five implements Four {
field: String
method(): void
}
@enduml
成员变量、成员方法
@startuml
class Hello {
one: String
three(param1: String, param2: int): boolean
String two
int four(List param)
}
@enduml
class定义后跟大括号,声明成员,然后按照 变量名:类型 的顺序声明,类型后置。方法和成员的顺序上可以混在一起,最终成图是,会自动分为两组
成员可见性UML 使用以下符号表示可见性
| Character | Visibility |
|---|---|
| - | private |
| # | protected |
| ~ | package private |
| + | public |
但是 PlantUML 将这种文字符合进一步图形化:
@startuml
class Hello {
- privateField: int
# protectedField: int
~ packagePrivateField: int
+ publicField: int
- privateMethod(): void
# protectedMethod(): void
~ packagePrivateMethod(): void
+ publicMethod(): void
}
@enduml
当然,也可以关闭这种图形化符合,继续使用文字符号
@startuml
skinparam classAttributeIconSize 0
class Hello {
- privateField: int
# protectedField: int
~ packagePrivateField: int
+ publicField: int
- privateMethod(): void
# protectedMethod(): void
~ packagePrivateMethod(): void
+ publicMethod(): void
}
@enduml
通过 skinparam classAttributeIconSize 0 关闭图形化符号
抽象方法@startuml
class Hello {
{abstract} one: int
{abstract} two(): int
}
@enduml
成员前面加 {abstract} 标记位抽象成员
静态方法@startuml
class Hello {
{static} ONE: int
{static} two(): int
}
@enduml
添加 {static} 表示静态方法
泛型@startuml class Helloclass World @enduml
类名后跟<泛型>
包图@startuml
package one.two {
class Hello
}
package three.four {
World -- Hello
}
@enduml
package
@startuml
package three.four {
World -- Hello
}
package one.two {
class Hello
}
@enduml
包图的顺序很重要,如上图 one.two 中的类被 three.four 依赖,所以应该写到先面, 以为 Hello 会声明在第一个出现的包中。
备注(note)@startuml class Fizz note left: fizz class Buzz note right: buzz class Foo note top: foo class Bar note bottom: bar @enduml
使用 note
@startuml Fizz -- Buzz note left of Fizz: fizz note right of Buzz: buzz @enduml
note <位置> of <目标>: <备注>用来为指定目标 Class 生成备注
为类关系进行备注@startuml Fizz -- Buzz note on link: fizz-buzz note left: buzz @enduml
note on link: <备注> 可以在类图的关系中添加备注
给备注加名字@startuml note "Hello World" as n1 Hello -- n1 World .. n1 note "Fizz Buzz" as n2 @enduml
note "<备注>" as <名字>用来给备注设置名字,有了名字后,可以通过名字将一个备注关联到多个Class
多行备注@startuml class Hello note left Hello World end note Fizz -- Buzz note on link Fizz Buzz end note note left of Fizz fizz buzz end note note as n1 Foo Bar end note @enduml
end note 用来结束多行的备注



