遇见 PlantUML~

本贴最后更新于 1716 天前,其中的信息可能已经斗转星移

前言

来到公司实习也快一个月了,最大的体会就是,虽然大部分时间做的是简单的增删该查,但不同于在学校时写的 Demo,你要充分考虑程序的鲁棒性(健壮性)、可扩展性(可维护性)、时间/空间复杂度等。因为是要实际上线的项目,你需要面面俱到,对团队负责。

于是决定在完成组里任务之余,花时间提高自己的的编码规范、多思考程序设计的可扩展性、性能是否可观等。我觉得开发工程师和码农之间的区别是,不仅是复制粘贴和以实现功能为最终目标,还要考虑如何更优雅的编码、如何实现代码复用而避免重复动作,这是一种追求,也能给工作带来一种工艺、匠心上的体验。

于是我想从设计模式下手,学习前辈们多年沉淀下来的优雅的编码技巧。之前曾看过《Head First 设计模式》,当时感觉写的挺好,但是急于求成,一味地莽着看完了,到现在回想起来却也不记得几分。我觉得实战和重复是学习的重要因素,纸上得来终觉浅,绝知此事要躬行,还是要花时间认真学一遍啊~

感觉《Head First 设计模式》中的内容针对 GUI 编程的较多,而现在 Java 主流应用在服务端,再加上看过的书除非是像《深入理解 Java 虚拟机》这种每每“”温故而知新”的,我不太愿意看第二遍,于是将目标定在了《图解 Java 设计模式》上。(本来上当当搜“Java 设计模式”发现《Java 设计模式及实践》好像还不错而且是针对 Java 服务端的,但奈何太新网盘上还搜不到 PDF 资源,而我又经济拮据……)

在看设计模式相关的书籍时总有一个感觉,当设计模式中的角色较多时很容易把自己搞混,这时一个清晰的 Java 类图能够高效的帮你理清思路以及如此设计的用意。于是我又折腾的下载了一个 IDEA 插件 PlantUML,自此 PlantUML 的入坑之路拉开序幕……

安装及配置

IDEA 插件

IDEA 中安装好 PlantUML 插件(和 markdown 插件类似,有自己的 UML 描述语言,在编写后能事实反应到 UML 图中)后,按照官方文档的提示 File->New->PlantUML File 开始我的第一个类图

1565688748017.png

然而,我在编写如上右侧的代码后,右边显示的确实一个异常:

1565688910081.png

这是因为 PlantUML 依赖 Graphviz,我们需要先下载它(该链接是 Windows 的 .msi 安装包,若是其它平台,可在参考 https://www.graphviz.org/download/

安装之后需要为其配置环境变量 GRAPHVIZ_DOT,为安装目录下的 /bin/dot.exe,如图

1565689168390.png

然后重启 IDEAPlantUML 标签窗口就能根据你输入的 PlangUML language 实时绘图了

1565689274652.png

PlantUML

上节是 PlantUML 作为插件在 IDEA 中的使用,作为独立的产品,自然也能够独立运行,本节就介绍通过运行 jar 的方式使用 PlantUML

首先下载该产品对应的 jar,然后在该 jar 所在路径运行 java -jar plantuml.jar 即可启动该应用:

1565690222139.png

然后点击 Change Directory 选择一个目录作为 workspace,这里我选的是 D:\Work_Space\UML,后续 PlantUML 源文件和对应生成的图片都将放在此目录。

workspace 中新建源文件,如 test.txt,键入如下代码:

@startuml
class HelloWorld
@enduml

保存后,在 GUI 中双击该文件即可打开对应的绘图窗口,并且每次保存源文件都会自动触发重新绘图:
1565690677576.png

类图

使用 PlantUML 可以画出很多中图,可参考官方文档,本文仅介绍 IDEA 中类图的画法。

类之间的关系

泛化/IS-A

IS-A 通常用来表继承关系,用空心三角形加实线来表示,语法为 Parent <|-- Child

@startuml
Person <|-- Child
@enduml

image.png

你也可以像下面写代码一样表述关系,extends 将被识别

@startuml
class Person{
    age : int
    gender : char
}

class Student extends Person{
    grade : String
}
@enduml

image.png

实现

实现一般针对接口,符号为三角形加虚线,语法为 Flyable <|.. Plane

@startuml
interface Flyable{
    void fly();
    {abstract} double getSpeed();
}

class Vehicle{
    int speed;
    {abstract} void run();
}

Flyable <|.. Plane
Vehicle <|-- Plane
@enduml

image.png

聚合 Aggregation

语法:空心菱形加实线 Department o-- Employees

Aggregation 聚合关系用于表示实体对象之间的关系,表示整体由部分构成的语义,例如一个部门由多个员工组成。与组合关系不同的是,整体和部分不是强依赖的,即使整体不存在了,部分仍然存在,例如:部门撤销了,人员不会消失,他们依然存在

@startuml
class Employee{
}

class Department{
    Employee[] employees;
}

Department o- Employee
@enduml

image.png

一个 - 会画横线,两个 - 会画竖线,如 o-- 会画竖线

组合 Composition

语法:实心菱形 + 实线 ArrayList *- Element

Composition 组合关系是一种强依赖的特殊聚合关系,如果整体不存在了,则部分也不存在了,例如:公司不存在了,部门也将不存在了

@startuml
class Element{

}

class ArrayList{
    Element[] elements
}

ArrayList *- Element
@enduml

image.png

由于在 Java 中,内存管理对于我们是透明的。不像 C 语言,可能我们调用 free(company) 释放结构体对象 company 的内存,那么其成员 departmentList 也会被销毁。Java 的自动内存管理机制是只要该对象到 GC Roots 是可达的(即能够与引用链连上)那就不会被回收。因此,在 Java 中,这两种关系的界限并不分明。

关联关系 Association

语法:实线 + 箭头,->/<-<--/--><->/<-->

关联关系是用一条直线表示的;它描述不同类的对象之间的结构关系;它是一种静态关系, 通常与运行状态无关,一般由常识等因素决定的;它一般用来定义对象之间静态的、天然的结构; 所以,关联关系是一种“强关联”的关系;

比如,乘车人和车票之间就是一种关联关系;学生和学校就是一种关联关系;

关联关系默认不强调方向,表示对象间相互知道;如果特别强调方向,如下图,表示 A 知道 B,但 B 不知道 A;

@startuml
class Controller{
    Service service;
}
class Service{
    Dao dao;
}
class Service2
class Dao
Controller -> Service
Service <-> Service2 
Service -> Dao
@enduml

image.png

依赖

语法:

依赖也容易和关联弄混,但与关联关系不同的是,它是一种临时性的关系,通常在运行期间产生,并且随着运行时的变化, 依赖关系也可能发生变化

显然,依赖也有方向,双向依赖是一种非常糟糕的结构,我们总是应该保持单向依赖,杜绝双向依赖的产生;

在最终代码中,依赖关系体现为类构造方法及类方法的传入参数,箭头的指向为调用关系;依赖关系除了临时知道对方外,还是“使用”对方的方法和属性;

@startuml
class UserController{
    void insertUser(User user)
}

class User{

}

UserController .> User
@enduml

image.png

关于类图的入门介绍到此为止,有兴趣的同学可参考官网进一步学习,并在学设计模式之后借助类图梳理流程和思路,以达到事半功倍的效果~

参考资料

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...