UML入门以及plantuml工具介绍
简介
UML,Unified Modeling Language,统一建模语言,是一种开放的方法,用于说明、可视化、构建和编写一个正在开发的、面向对象的、软件密集系统的制品的开放方法。——维基百科
模型
- 功能模型:从用户的角度展示系统的功能,包括:用例图。
- 对象模型:采用对象,属性,操作,关联等概念展示系统的结构和基础,包括:类图、对象图。
- 动态模型:展现系统的内部行为。包括:序列图,活动图,状态图。
工具
- Rose
- EA
- processon 在线协作绘图平台,为用户提供最强大、易用的作图工具,支持在线创作流程图、BPMN、UML图、UI界面原型设计、iOS界面原型设计、泳道图等。可以共享方便团队协作,但是有只能绘制9张图的限制,导出文件不可编辑。
- Plant UML,基于graphviz的一款绘图工具,强大。
- planttext 在线绘图,支持导出,可以自建一个服务器生成图片。使用在线生成工具的好处是不用保存图片,可以直接应用生成的图片地址。
- gravizo,同样基于graphviz,有待试用研究。
类图
类图是UML的灵魂。想要画好类图,就要学会给类图分出不同的组,分成不同的包。分组的规则就是跟三层架构的层是一一对应的。纯三层——UI、BLL、DAL这三层再加上一个Entity(实体)层。
- UI层
用户界面对应的类。这些窗体类一般既没有方法也没有属性,它们只是通过事件(如单击事件等)来调用 BLL 层里面的方法。 - Entity层
实体层里面的类跟数据库里面的表是一一对应的,即一张表一个实体类,实体类同样没有方法,但是它有自己的属性。它的属性就是表里面每一列的每个字段。 - DAL层
用来跟数据库打交道,所以它跟实体层一样,也是与数据库中的表是一一对应的。而它所具有的方法就是对数据简单的增删改查。 - BLL层
Business Logic Layer:这一层就是上面三个层之间的一个桥梁,负责它们之间的数据交换,通常情况只有方法没有属性,其方法就是窗体所具有的功能(一个功能可能包含一个或多个方法)。
类图是软件工程的统一建模语言一种静态结构图,该图描述系统的类集合,类的属性和类之间的关系。是系统分析和设计阶段的重要产物,也是系统编码和测试的重要模型依据。
在UML类图中,类使用包含类名,属性,方法名及其参数并且用分割线分隔的长方形表示。通过Person的类图,可以看出类图有三部分组成,类名,属性和方法。若是抽象类,在类名右上角会有一个(Abstract)表示。
UML中的属性名就是Java中的成员变量。Java类中成员变量的修饰符,类型和默认值都可以在UML类图中体现出来。通用表示方法如下:
可见性
名称:类型 [ = 默认值 ]
在Java类中可见性分为三类,分别是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
- 1
- 2
- 3
依赖
依赖,是类与类之间最弱的关系,依赖可以简单的理解一个类使用另一个类,这种使用关系具有临时性特征,但一个类又会由于另一个类的改变而受到影响。表现在代码层面,为类B作为参数被类A在某个method中使用,一般指由局部变量、函数参数、返回值建立的对于其他对象的调用关系。一个类调用被依赖类中的某些方法而得以完成这个类的一些职责。用带箭头的虚线表示依赖,箭头从使用类指向被依赖的类。
如:Human
..> Cigarette
关联
关联,描述不同类的对象之间的结构关系;它是一种静态关系,
通常与运行状态无关,一般由常识等因素决定的;一般用来定义对象之间静态的、天然的结构;是一种强关联的关系。这种关系通常使用类的属性表达。关联又分为一般关联、聚合关联与组合关联。表现在代码层面,为被关联类B以类属性(成员变量)的形式出现在关联类A中。表示一个类和另一类是一种包含关系。用带箭头的实线表示,箭头指向被包含类(箭头从使用类指向被关联的类)。分为:1..1
表示另一个类的一个对象只与该类的一个对象有关系,0..*
表示另一个类的一个对象与该类的零个或多个对象有关系,1..*
表示另一个类的一个对象与该类的一个或多个对象有关系,0..1
表示另一个类的一个对象没有或只与该类的一个对象有关系,*
任意多个对象关联。关联关系默认不强调方向,表示对象间相互知道。
class Water
class Human
Human --> Water
- 1
- 2
- 3
聚合
聚合,关联关系的一种特例,表示整体与部分、拥有的关系,即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]
对消息进行说明。垂直的虚线叫做生命线,代表一个对象的存在时间。每一个箭头都是一个调用,生命线上白色的条叫做激活条,激活条代表的就是这次调用持续的时间
用例图
参与者与用例的交互,主要作用是来收集系统需求,包括内部和外部的影响(例如此系统的用户分为n种角色,每一个角色所能干的事)。
活动图
当流程图来用,描述程序的处理过程。
组件图
表示组件是如何互相组织以构建更大的组件或是软件系统。
状态图
描述对象从开始到结束的状态改变。
实例:
[*] -> 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;
- 1
- 2
- 3
- 4
- 5
- 6
效果:
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
安装
PlantUML 依赖 Graphviz,Windows
下载安装 graphviz,选择 msi 安装包或者 zip压缩包;Mac
安装:brew
install graphviz
。注意:无论是 sublime 还是 IDEA
想要借助 plant UML绘制 UML 图,都需要先安装 Graphviz。
PlantUML
提供 IDEA 插件:plantuml integration,安装好后重启IDEA。在 IDEA other setting 中更改配置即可。
sublime
安装 plantUML 参考我的博客:Sublime
入门使用教程
入门
随便新建一个文本文件,比如demo.txt(后缀名随意):
@startuml
' 单引号开头,注释内容
/' 另一种形式的注释 '/
' 实例展示类图访问权限控制:- # ~ + 分别表示 private、protected、package、public
' 使用 skinparam classAttributeIconSize 0关掉icon的显示;
' 使用{static}或者{abstract}来修饰字段或者方法,修饰符需要在行开头或者末尾;可以使用{classifier}代替{static}
' 加粗:<></b> 换行:
该表字体 font 大小: <size:nn>
' 使用 title 或者 title end title 表明标题
title some silly example
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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
渲染效果图:
其他UML示例:我的 GitHub
也可以在
chrome 中安装 plant UML 插件的形式来集成使用。
语法
参考PDF:http://plantuml.com/PlantUML_Language_Reference_Guide.pdf
绘图的内容需要包含在@startuml和@enduml中。保存绘图文本格式不限,如
demo.txt 都行,然后可以使用命令行:java
-jar /path/to/plantuml.jar -tsvg demo.txt
即可在当前路径生成同名 demo.svg
的图片。也可以生成PNG、SVG、LaTeX和二进制图片。修改选项-t
即可。