用PlantUML和语雀画UML类图
概述
首先阐述一下几个简单概念:
- UML:是统一建模语言(Unified Modeling Language)的缩写,它是一种用于软件工程的标准化建模语言,旨在提供一种通用的方式来可视化软件系统的结构、行为和交互。UML由Grady Booch、Ivar Jacobson和James Rumbaugh三位软件工程专家在1990年代初共同开发,并在1997年被对象管理组织(Object Management Group, OMG)正式采纳。
- PlantUML:是一个开源工具,它允许我们用文本形式来描绘和创建UML图。在VSCode中可以安装扩展来绘制,而在语雀的MarkDown编辑器中,则可以用“文本绘图”形式直接在文档中创建。
- UML类图:在面向对象语言或开发中类图是最基础也最有用的一种图,它可以描述类的成员以及多个类之间的关系。
在Godot中,我们使用GDScript进行游戏或类库开发时,也需要涉及面向对象开发和类图等,用于清晰表达自己的思路或详实自己的文档。
因为语雀文档内部创建更方便,所以本文主要介绍在语雀中绘制UML类图的方式。
在语雀中创建PlantUML类图
在语雀文档中,在任意一行行首输入“/wbht”,可以找到“文本绘图”,回车即可插入“文本绘图”的Block。

默认插入的“文本绘图”块如下:

点击顶部的“模板”,在下拉列表中选择“类图”:

会自动填充和渲染一个如下的类图:

我们便可以在这个基础上进行UML类图的绘制。
PlantUML类图基础语法
起止标记
首先是起止标记,绘图描述的内容必须包裹在一对@startuml和@enduml标记之间。
@startuml@enduml
申明元素
在@startuml和@enduml标记之间,我们可以使用特定的语法来申明类图的元素。PlantUML本身支持很多种元素申明,详见:类图的语法和功能
但在GDScript中最常用到的便是类和枚举,其他的元素类型并不支持。
@startuml
class a
enum skills
@enduml
其中:
- 以
class为关键字,后面跟类名,可以声明一个类; - 以
enum为关键字,后面跟枚举名,可以声明一个枚举;
上面代码生成的类图如下:

添加类或枚举的成员
以类为例,我们可以使用:(注意前后都有一个空格)来为申明的类添加成员,名称不带()的被视为是属性,带()的被视为是方法。
@startuml
class a
a : name
a : sex
a : age
a : say_hello()
@enduml
上面的代码生成的类图如下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1zKGwWHp-1720151404747)(https://i-blog.csdnimg.cn/direct/e94e04d6b32e4fe0ada960213df64dba.png)]](https://i-blog.csdnimg.cn/direct/74e9c8fe7db34e3fbe1451abf6104e02.png)
也可以用花括号语法:
@startuml
class a{namesexagesay_hello()
}
@enduml
这样的写法更接近于真实代码的形式,可以省去重复的类名和:。
申明成员类型
可以为类的成员申明数据类型。
@startuml
class a{String namebool sexint agevoid say_hello()
}
@enduml
可以采用C风格的前置类型声明:

也可以采用类似GDScript的冒号后置类型申明形式:
@startuml
class a{name:String sex:boolage:intsay_hello():void
}
@enduml

设定成员的可访问性
类图可以更具体的标记属性和方法的可访问性,也就是private、protected、public,如果是C++之类的或许可以用上,但是在GDScript中并不涉及这部分。
下面是具体的修饰符和意义。
| 字符 | 图标(属性) | 图标(方法) | 可访问性 |
|---|---|---|---|
| - | ![]() | ![]() | private 私有 |
| # | ![]() | ![]() | protected 受保护 |
| ~ | ![]() | ![]() | package private 包内可见 |
| + | ![]() | ![]() | public 公有 |
下面是一个简单的例子:
@startuml
class a{+name:String -sex:bool~age:int+say_hello():void
}
@enduml
绘制效果如下:

表示静态变量或方法
Godot3.x就支持静态函数,Godot4.x更是支持了静态变量。
在PlantUML类图中我们可以精确的表示静态函数和静态变量成员,以与非静态成员区分。
方法也很简单就是在静态成员之前添加{static}修饰符。
@startuml
class a{+ {static} name:String -sex:bool~age:int+{static}say_hello():void
}
@enduml
绘制效果如下:

可以看到静态成员的名称下添加了下划线。
使用分隔线对成员进行自定义分组
可以在成员之间用--、..、==、__进行自定义分割线的绘制
@startuml
class a{ame:String --sex:bool==age:int..say_hello():void__say_yes():void
}
@enduml
实际效果如下:

可以看到:
--是一条比较粗的横线,__是一条比较细的横线==是双横线..是虚线
你也可以在分割线基础上进行分组的命名。
@startuml
class a{ame:String -- 性别 --sex:bool== 年龄 ==age:int.. 方法 ..say_hello():void__ 还是方法 __say_yes():void
}
@enduml
绘制效果如下:

这样我们可以将成员进行分组,让类的结构更清晰易懂。
多个类之间的关系表示
| 关系类型 | 符号 | 绘图 |
|---|---|---|
| 泛化关系 | <|– | ![]() |
| 组合关系 | *– | ![]() |
| 聚合关系 | o– | ![]() |
--代表实线,可以用..替代表示虚线。<|、*和o分别代表箭头的类型
类与类之间的关系可以查阅相关的视频或文档,这里不做赘述,这里只举例说明继承关系的表示。
@startuml
Car <|-- Bus
@enduml
这里我们直接省略class关键字,申明了Car和Bus两个类,并且使用<|--连接它们。
生成的类图如下:

它的含义就是,Car作为父类,Bus作为子类,Bus继承自Car。
- 新手注意:继承关系的箭头是由子类指向父类。
我们可以继续这个例子,添加Car的其他子类型:
@startuml
Car <|-- Bus
Car <|-- motorcycle
Car <|-- bicycle
@enduml
生成类图如下:

在箭头连线上添加文本
可以在整个箭头连线关系的最后,在:后面添加文本信息,用于显示在连线上。
@startuml
Car <|-- Bus:继承自
Car <|-- motorcycle:继承自
Car <|-- bicycle:继承自
@enduml
生成类图如下:

表示类之间的数量关系
也可以用双引号,在连线的起始端和末尾端添加文本,用于表示类似ER(实体关系图)中的“一对一”、“一对多”、“多对多”等关系。
在继承关系中可能使用这种描述不太恰当,可以在“组合”或“聚合”等关系中使用。
下面的代码表示,一个汽车有4个轮子组成:
@startuml
汽车 "1" *-- "4" 轮子:组成
@enduml
生成类图如下:

控制类绘制的位置
在连线之间可以使用up、down、left和right关键字来手动控制类的绘制位置。
以之前的Car派生的例子为例:
@startuml
Car <|-- Bus:继承自
Car <|-- motorcycle:继承自
Car <|-- bicycle:继承自
@enduml
默认绘制为:

通过在表示实线的--之间,指定上下左右方位的关键字:
@startuml
Car <|-left- Bus:继承自
Car <|-up- motorcycle:继承自
Car <|-right- bicycle:继承自
@enduml
就可以将类图渲染为如下形式:

绘制备注
note关键字用于绘制备注。
可以使用note 位置 of 元素的形式,为类、枚举或者其他类图元素设定备注。
@startuml
Car <|-left- Bus:继承自
Car <|-up- motorcycle:继承自
Car <|-right- bicycle:继承自note bottom of Car:车,基类
note bottom of Bus:公共汽车
note bottom of bicycle:自行车
note left of motorcycle:摩托车
@enduml
绘制效果如下:

还有一种写法,可以省略of 元素,但是需要紧跟在class申明之后,或者指定两个类的关系之后。
@startuml
class Car
note bottom:车,基类Car <|-left- Bus:继承自
note bottom:公共汽车Car <|-up- motorcycle:继承自
note left:摩托车Car <|-right- bicycle:继承自
note bottom:自行车
@enduml
绘制效果如下:

可以看到效果基本上无异。
还可以用note "备注内容" as 变量形式将备注申明为一个类似单独元素的东西。
再使用--或..进行连接:
@startuml
class Car
note "车,基类" as N1
Car -- N1
@enduml
效果如下:

另外,在备注中,可以使用\n进行多行文本的换行控制。
为类图添加标题
使用title关键字可以为类图添加标题。
@startuml
title 车类的继承关系类图
Car <|-left- Bus:继承自
Car <|-up- motorcycle:继承自
Car <|-right- bicycle:继承自note bottom of Car:车,基类
note bottom of Bus:公共汽车
note bottom of bicycle:自行车
note left of motorcycle:摩托车
@enduml
绘制效果如下:

为类图添加页脚
如果你不喜欢顶部的标题,可以使用footer关键字指定一个底部的页脚。
@startumlCar <|-left- Bus:继承自
Car <|-up- motorcycle:继承自
Car <|-right- bicycle:继承自note bottom of Car:车,基类
note bottom of Bus:公共汽车
note bottom of bicycle:自行车
note left of motorcycle:摩托车
footer 车类的继承关系类图
@enduml
绘制效果如下:

Godot中的一些类图实例
上面我们已经学习了如何用PlantUML进行类图的绘制。下面就举一些Godot中的例子。
子类与父类(继承关系)
@startumlControl <|-- Button
note bottom:泛化关系(继承关系)\n子类指向父类,\n实线空心三角箭头@enduml
绘图效果:

成员引用(一般关联关系)
@startumlclass class01{attr:class02
}class01 --> class02
note bottom:单向关联关系\n引用者指向被引用者class class03{attr:class04
}class class04{attr:class03
}class03 -- class04
note bottom:双向关联关系\n箭头消失class class05{sub_itm:class05
}class05 --> class05
note bottom:自关联关系\n自己的成员变量引用自己@enduml
绘制效果:

部分与整体(聚合与组合)
@startumlclass Player {
}
note left:玩家
Player -up-|> CharacterBody2D
Player o-- CollisionShape2D
note bottom:碰撞形状
Player o-- Sprite
note bottom:玩家长相
@enduml
绘制效果:

更复杂的可以有:
@startuml
title Godot中2D角色的节点组成结构(2)
class Player {
}
note left:玩家
Player -up-|> CharacterBody2D
Player o-- CollisionShape2D
note bottom:碰撞形状
Shape2D <-down- CollisionShape2D
Player o-- HitBox
note bottom:攻击判定区域
HitBox -up-|> Area2D
CollisionShape2D2 -down-o HitBox
Shape2D <-down- CollisionShape2D2Player o-- Sprite
note bottom:玩家长相
@enduml

组合关系
@startuml
title Godot中的组合关系
class Tree {
}Tree *-- TreeItem
note right:组合关系,\n父类由子类组成,\n父类消失,子类失去意义,\n子类消失,父类无法构成。@enduml

依赖关系
@startuml
title Godot中类的依赖关系
class ShapePoints {
+static rect():PackedVector2Array
}class myCanvas{
+ draw_rect():void
}ShapePoints <.. myCanvas
note right: 依赖关系:\n一个类用**局部变量**、\n**方法参数**或者\n**对静态方法的调用**\n来访问另一个类@enduml

总结
本文带领Godot使用者,学习和使用基础的PlantUML类图绘制技巧。
希望对Godoter们编写和设计自己的类以及类库有所帮助,你也可以用来绘制和讲解设计模式等。
本文不详之处,可以查阅其他大佬的文章或翻找PlantUML官方文档。
若有错误之处,还请指正。
相关文章:
用PlantUML和语雀画UML类图
概述 首先阐述一下几个简单概念: UML:是统一建模语言(Unified Modeling Language)的缩写,它是一种用于软件工程的标准化建模语言,旨在提供一种通用的方式来可视化软件系统的结构、行为和交互。UML由Grady…...
uniapp微信小程序电子签名
先上效果图,不满意可以直接关闭这页签 新建成单独的组件,然后具体功能引入,具体功能点击签名按钮,把当前功能页面用样式隐藏掉,v-show和v-if也行,然后再把这个组件显示出来。 【签名-撤销】原理是之前绘画时…...
MetaPoint_速读
Meta-Point Learning and Refining for Category-Agnostic Pose Estimation https://arxiv.org/abs/2404.14808https://github.com/chenbys/metapointabstract 这篇文章介绍了一种名为Meta-Point Learning and Refining的框架,用于实现类别不可知的姿势估计。该框…...
数据库逆向工程工具reverse_sql
reverse_sql 是一个用于解析和转换 MySQL 二进制日志(binlog)的工具。它可以将二进制日志文件中记录的数据库更改操作(如插入、更新、删除)转换为反向的 SQL 语句,以便对系统或人为产生的误操作进行数据回滚和恢复。 *…...
四大内网穿透利器对比
本文精选四款市场上的佼佼者——巴比达、花生壳、Frp及NatApp,详细剖析它们的特点与优势,助力企业和个人用户精准选择,其中特别强调了巴比达在企业级安全访问方面的突出贡献。 1. 巴比达 特点 深度安全防护:巴比达提供全方位安…...
【LeetCode】每日一题:跳跃游戏 II
给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i j] 处: 0 < j < nums[i] i j < n 返回到达 nums[n - 1] 的最小…...
SpringBoot拦截器
目录 一、拦截器快速入门 (1)什么是拦截器 (2)拦截器的使用步骤 1、定义拦截器 🍀preHandle() 方法 🍀postHandle() 方法 🍀afterCompletion() 方法 2、注册配置拦截器 二、拦截器详解…...
uniapp中实现跳转链接到游览器(安卓-h5)
uniapp中实现跳转链接到游览器(安卓-h5) 项目中需要做到跳转到外部链接,网上找了很多都不是很符合自己的要求,需要编译成app后是跳转到游览器打开链接,编译成web是在新窗口打开链接。实现的代码如下: 效果&…...
WPF UI 界面布局 魔术棒 文字笔记识别 技能提升 布局功能扩展与自定义 继承Panel的对象,测量与排列 系列七
应用开发第一步 功能分类:页面上的功能区域划分。。。。需求分析 业务逻辑 数据流 功能模块 UI/UX 编码 测试 发布 功能开发与布局 不用显式的方式设定元素的尺寸 不使用屏幕坐标来指定位置 Grid 功能最强大,布局最灵活的容器…...
文件格式是.pb应该怎么查看?
文件格式为.pb的文件,通常是Google Protocol Buffers(简称PB)序列化后的二进制文件。要查看.pb文件的内容,可以采用以下方法: 1. **直接打开(不推荐)**: - 直接打开.pb文件通常会显示…...
android2024 gradle8 Processor和ksp两种编译时注解实现
android编译时注解,老生常谈,外面的例子都是bindView,脑壳看疼了,自己学习和编写下。 而且现在已经进化到kotlin2.0,google也逐渐放弃kapt,进入维护状态。所以要好好看看本贴。 参考我的工程: h…...
elementui的table的@selection-change阻止事件改变
说明: 最近有个不想说的(xxx)业务,在表格勾选每一行的时候要触发一系列查询功能,查询失败还要把那个勾勾回退。真实蛋疼!表格勾选的默认selection-change是change事件,一般change事件是在完成之…...
空间数据采集与管理:为什么选择ArcGISPro和Python?
你还在为找不到合适的数据而苦恼吗?你还在面对大量数据束手无策,不知如何处理吗?对于从事生产和科研的人员来说,空间数据的采集与管理是地理信息系统(GIS)和空间分析领域的关键环节。通过准确高效地采集和管…...
案例精选 | 聚铭综合日志分析系统为江苏省电子口岸构建高效安全的贸易生态
江苏省电子口岸有限公司,成立于2009年,由江苏省贸促会携手南京海关、江苏检验检疫局及江苏海事局等部门共同出资组建。公司承载着推动江苏乃至长三角地区国际贸易便利化的重大使命,致力于打造一个集先进性、创新性、高效性于一体的电子口岸综…...
TCP粘包
目录 TCP粘包产生的原因 TCP粘包的现象 TCP粘包的解决方案 TCP粘包是指在TCP通信中,发送方发送的多个数据包在接收方被错误地合并成一个数据包的现象。tcp粘包在发送端和接收端都有可能发生。发送端粘包:发送端需要等缓冲区满才发送出去,造成粘包。接收方粘包:接收方不及…...
数据泄露态势(2024年5月)
监控说明:以下数据由零零信安0.zone安全开源情报系统提供,该系统监控范围包括约10万个明网、深网、暗网、匿名社交社群威胁源。在进行抽样事件分析时,涉及到我国的数据不会选取任何政府、安全与公共事务的事件进行分析。如遇到影响较大的伪造…...
二手闲置平台小程序的设计
管理员账户功能包括:系统首页,个人中心,用户管理,卖家管理,商品分类管理,商品信息管理,商品购买管理,商品配送管理 微信端账号功能包括:系统首页,商品信息&a…...
协程libgo的使用
c开源协程库libgo介绍及使用-CSDN博客 libgo库的github地址:GitHub - yyzybb537/libgo: Go-style concurrency in C11 使用libgo编写并行程序,即可以像golang一样开发迅速且逻辑简洁,又有C原生的性能优势。它的特点有: 1.提供go…...
什么叫低频晶振?低频晶振最低频率能达到多少?低频晶振封装尺寸有哪些?
低频晶振指的是那些工作在较低频率范围内的晶体振荡器,通常这类振荡器的标称频率低于8MHz。这些晶振在各种电子设备中都有应用,尤其是在那些需要精确但不需要高频振荡的应用场景中,比如实时时钟(RTC)、低速串行通信接口(如UART、IC等)、以及一…...
Splunk Enterprise 任意文件读取漏洞(CVE-2024-36991)
文章目录 前言漏洞描述影响版本漏洞复现POC批量检测-nuclei脚本 修复建议 前言 Splunk Enterprise 是一款强大的机器数据管理和分析平台,能够实时收集、索引、搜索、分析和可视化来自各种数据源的日志和数据,帮助企业提升运营效率、增强安全性和优化业务…...
【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)
前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 编辑 前言: 类加载器 1. …...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...
elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...
tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...











